I've got a Rails app that doesn't seem to be triggering the expectedly named .js.erb file, so I'd like to override the default behavior, but I'm not sure how.
The details:
It's a Rails 3 app that renders a button_to with an AJAX call to toggle the status of something on the backend and then modifies the text of the button to reflect the reverse action if you click on it again. Basically 'Save to schedule' becomes 'Remove from schedule' and you can click on it again to do the opposite.
This actually works fine, but only if I put the jQuery I want executed into show.js.erb (named after the view associated with the method that shows the page where the button is on) and not toggle.js.erb (based on the name of the actual method being called).
In this example, I'm using jquery-rails.
From the view that renders the button (show.html.erb
(more specifically, a partial called from there):
<% if current_user.shows.include?(@show) %>
<p><%= button_to "Remove from schedule", toggle_show_path(@show), :remote => true, :class => 'schedule_button' %>
<% else %>
<p><%= button_to "Save to schedule", toggle_show_path(@show), :remote=> true, :class => 'schedule_button' %>
<% end %>
From routes.rb
:
match '/shows/toggle/:id' => 'shows#toggle', :as => :toggle_show
From my `shows_controller.rb:
def toggle
if current_user
show = Show.find(params[:id])
if show
if current_user.shows.include?(show)
current_user.shows.delete(show)
flash[:notice开发者_JS百科] = "This show has been removed from your schedule."
else
current_user.shows << show
flash[:notice] = "This show has been added to your schedule."
end
else
flash[:error] = "Unknown show."
end
else
flash[:error] = "You're not logged in."
end
end
I imagine there are some defaults conventions going on here that dictate which .js.erb file to use, but why isn't it using the one based on the method that the form submitted to?
I've been experimenting with telling it explicitly what to do, but I'm not quite sure how to specify the name of my alternate .js.erb file to be invoked. This doesn't seem to be it:
respond_to do |format|
format.html { redirect_to show_path(params[:id]) }
format.js { render toggle_show_path(params[:id]) }
end
From my log:
ActionView::MissingTemplate (Missing template /shows/toggle/22 with {:handlers=>[:erb, :rjs, :builder, :rhtml, :rxml], :formats=>[:js, :html], :locale=>[:en, :en]} in view paths "/Data/Sites/tvgridthing.local/app/views", "/Users/jschuur/.rvm/gems/ruby-1.9.2-p0/gems/devise-1.1.3/app/views", "/Data/Sites/tvgridthing.local", "/"):
app/controllers/shows_controller.rb:78:in `block (2 levels) in toggle'
app/controllers/shows_controller.rb:76:in `toggle'
I'm assuming since I want to override the default behavior, I can no longer use Rails 3's shorter 'respond_with format?
Unrelated question: Any way to condense my logic for adding/removing the show to my user model? I'm doing a find, an include and and add/delete and wonder if there's a simpler solution.
Update: I just figured this out with the help of someone else I sent this link to. The solution was simply: render :toggle
.
Still curious if any has suggestions about optimizing the toggle logic.
If you change
format.js { render toggle_show_path(params[:id]) }
To just
format.js
It will go by default to the file called toggle.js.erb
in the folder views/shows since you are inside the method toggle in the controller.
If you are inside the method show then yes your only solution is
render :toggle
Or
render :action => 'toggle'
Hope this helps
精彩评论