Dave Smylie Dave Smylie - 1 month ago 5
Ajax Question

Rails upgrade to 3.1 - changing ajax handling from "render :update" to respond_to

I'm upgrading a old rails app to 3.1. The app is pretty much working, but I have some ajax functionality I need to update. (If it makes any difference I'm using jquery and coffeescript)

All of the existing ajax functionality was written using render :updates. eg

render :update do |page|
page.remove "financial_tran_offset_#{params[:ftof_id]}"
page.replace_html 'details', :partial => 'details', :locals => {:obj => @fire}
end


I think the new preferred way of doing this is to use a respond_to? block to handle the js, but I'm not sure of the best way of handling these different cases.

For the first case (the
page.remove
) I think with the asset pipe line, I should have an external js in /app/assets/javascripts/ to handle the javascript side (eg the page.remove) but I'm not sure how to pass the parameters to the js file. I'm guessing you can do something like:

respond_to do |format|
format.js {:render :js => {:ftof => params[:ftof_id]}
end


but I'm not sure how you could pick this up from inside the js file. Is this right way to pass information to the js? Or is there another method I should be using?

For the second case (the
page.replace_html
) I think this has been deprecated/removed from 3.1 (according to apidock). I suspect again this should be using the js file in the app/assets/javascript directory, but not sure how I should go about rendering the partial and passing this information into the js.

Thanks for any pointers in this area =)

Answer

Use jQuery in conjunction withjs.erb views and respond_to blocks.

Whatever this action is (we'll say FoosController#update for the sake of example):

render :update do |page|
  page.remove "financial_tran_offset_#{params[:ftof_id]}"
  page.replace_html 'details', :partial => 'details', :locals => {:obj => @fire}
end

would become:

respond_to do |format|
  format.html
  format.js     # <- this is what we're after
end

with a view file update.js.erb:

$('#financial_tran_offset_<%= params[:ftof_id] %>').remove();
$('#details').replaceWith('<%= escape_javascript(render(:partial => 'details', :locals => {:obj => @fire})) %>');

update.js.erb will be parsed by ERb, rendered as JS, sent back to the client via Ajax and eval'd.

You can pass anything you want to these JS templates. After all, they are ERb files. Use <%= %> and instance variables as you would with HTML/ERb views. If you call render in your JS/ERb views, wrap it with escape_javascript to get HTML to render correctly.


render :update calls old JavaScriptGenerator helper methods for Prototype. Conversion to jQuery is pretty simple since they both do the same thing: select a DOM element and manipulate it.

Here's a nice little translation table with typical manipulations. Remove Prototype helper methods from the controller, and place their jQuery or JS counterpart in a corresponding JS/ERb view:

       Prototype                            jQuery/Javascript
     in controller                    in JS/ERb view (xxxxxx.js.erb)
       ---------                            -----------------
page.alert "message"                 alert('message');
page.hide "id"                       $('#id').hide();
page.insert_html \
         :top,    "id", "content"    $('#id').prepend('content');
         :bottom, "id", "content"    $('#id').append('content');
         :before, "id", "content"    $('#id').before('content');
         :after,  "id", "content"    $('#id').after('content');
page.redirect_to "url"               window.location.href = 'url';
page.reload                          window.location.reload();
page.remove "id"                     $('#id').remove();
page.replace "id", "content"         $('#id').replaceWith('content');
page.replace_html "id", "content"    $('#id').html('content');
page.show "id"                       $('#id').show();
page.toggle "id"                     $('#id').toggle();

Don't forget your semicolons on each and every line!