开发者

Overriding the JavaScript template used in a Rails remote form submission

开发者 https://www.devze.com 2023-01-19 03:13 出处:网络
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.

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

0

精彩评论

暂无评论...
验证码 换一张
取 消