handling ajax callbacks in rails3 using jquery

Previously, in rails 2.3.8 i used the prototype-helpers link_to_remote and form_remote_for (amongst others). These had the option to add callbacks as follows: [ruby] link_to_remote "Add to cart", :url => { :action => "add", :id => product.id }, :update => { :success => "cart", :failure => "error" } [/ruby] (an example from the documentation). This example would, upon success update the html-element with class "cart", and upon failure the class "error". The possible callbacks were:

  • :loading: Called when the remote document is being loaded with data by the browser.
  • :loaded: Called when the browser has finished loading the remote document.
  • :interactive: Called when the user can interact with the remote document, even though it has not finished loading.
  • :success: Called when the XMLHttpRequest is completed, and the HTTP status code is in the 2XX range.
  • :failure: Called when the XMLHttpRequest is completed, and the HTTP status code is not in the 2XX range.
  • :complete : Called when the XMLHttpRequest is complete (fires after success/failure if they are present). Now the modus operandi has changed, instead we write: [ruby] link_to "Add to cart", :url => {:action => "add", :id => product.id}, :remote => true [/ruby] and it seems there is no option to set the callbacks anymore. Instead of a normal html, we now render javascript, like this (in jquery) : [ruby] $('.cart').replaceWith(<%= escape_javascript(render :partial => 'cart') %>) [/ruby] But how do you handle an error situation? Do i handle it in my controller, and use seperate views? It would seem useful to me to somehow be able to mimic the behaviour we had before. Luckily in this article I was able to find the solution. I had already found that in rails.js the following callbacks were checked:
  • ajax:beforeSend : triggered before executing the AJAX request
  • ajax:success : triggered after a successful AJAX request
  • ajax:complete : triggered after the AJAX request is complete, regardless the status of the response
  • ajax:error : triggered after a failed AJAX request, as opposite to ajax:success But i had no idea how to provide these callbacks. The javascript should be unobtrusive, so this coupling is not done straight in the HTML anymore. From the same article i found a very clear example how to solve this. Take the following Rails 2.3.8 code : [ruby] <% form_remote_tag :url => { :action => 'run' }, :id => "tool-form", :update => { :success => "response", :failure => "error" }, :loading => "$('#loading').toggle()", :complete => "$('#loading').toggle()" %> [/ruby] That translates to this in Rails3 : [ruby] <% form_tag url_for(:action => "run"), :id => "tool-form", :remote => true do %> [/ruby] and inside some javascript (application.js), you bind the events [javascript] jQuery(function($) { // create a convenient toggleLoading function var toggleLoading = function() { $("#loading").toggle() }; $("#tool-form") .bind("ajax:beforeSend", toggleLoading) .bind("ajax:complete", toggleLoading) .bind("ajax:success", function(data, status, xhr) { $("#response").html(status); }); }); [/javascript] For completeness, here is a list of the events and their expected parameters: [javascript] .bind('ajax:beforeSend', function(xhr, settings) {}) .bind('ajax:success', function(data, status, xhr) {}) .bind('ajax:complete', function(xhr, status) {}) .bind('ajax:error', function(xhr, status, error) {}) [/javascript] [UPDATED 7/2/2012] Updated to reflect the new event-names. :loading was renamed to :beforeSend, and :failure was renamed to :error.

sampath 2010-09-17 19:10:37 UTC

hi, I have implemented above code week before. but I got following error. Template is missing Missing template hotel/search with {:locale=&gt;[:en, :en], :handlers=&gt;[:builder, :rjs, :erb, :rhtml, :rxml, :haml], :formats=&gt;[:html]} in view paths inside the search action, im using partials. i think that was the issue. please help me to solve the issue. when i call localhost:3000/search, its producing error. only error when use Jquery (AJAX). thanks

Nathan 2010-09-18 21:33:57 UTC

Hi Sampath, with only an error without any context i can't help you. The only thing i can guess, is that when using partials your view name starts with an underscore. So <code>render :partial => 'search'</code> actually needs a view called <code>_search</code>. But I could be way off. If you show me the controller-code and view-code i could shed more light. Kind regards, Nathan

Andrew 2010-12-21 09:09:20 UTC

Nice article! What if you want to include the object id like this : (#mydiv_) I can't seem to get the this to work in the application.js file.

Andrew 2010-12-21 09:11:01 UTC

Oops - your form stripped out my code -

Nathan 2010-12-21 13:00:26 UTC

Hi Andrew, not entirely sure what you mean, but i guess you would just replace the <tt>$('#response')</tt> in the last piece of code, by <tt>$('#my_div')</tt>. Doesn't that work for you?

Eduardo 2011-09-04 18:47:48 UTC

First of all, nice article, I was looking exactly for an example using "toggle" function because Im migrating a 2.3.5 Rails app to 3.0.3. Im having a problem "$("my-form").bind is not a function" pointing to the line in which I have ".bind("ajax:loading", toggleAll)"

Jon 2012-02-07 18:13:28 UTC

FYI, in newer versions of rails 3 (at least 3.2.1, but possibly earlier), ajax:loading has changed to ajax:beforeSend. See http://www.alfajango.com/blog/rails-3-remote-links-and-forms/

nathanvda 2012-02-07 21:31:13 UTC

Hi Jon, indeed I have kept my stackoverflow question and answer (http://stackoverflow.com/questions/3501317/rails3-rails-js-and-jquery-catching-success-and-failure-of-ajax-requests) better up to date than this post. Good reminder to up date this blogpost too.

Add comment

Recent comments


ruby on rails 34 ruby 26 rails3 17 rails 15 oracle 11 rspec 9 rspec2 7 jquery 7 ubuntu 5 javascript 5 windows 5 activerecord 3 refactoring 3 geoserver 3 gis 3 arrrrcamp 3 actionmailer 2 oracle spatial 2 tdd 2 postgis 2 routing 2 rvm 2 mongoid 2 csharp 2 thin 2 win32 2 gem 2 rails4 2 git 2 service 2 haml 2 cucumber 2 view testing 2 i18n 1 displaysleep 1 spatial 1 gemsets 1 wubi 1 oracle_enhanced_adapter 1 migrations 1 watchr 1 ci 1 plugins 1 coderetreat 1 ie8 1 ssl 1 oci 1 nested model form 1 wcf 1 11.04 1 jsonp 1 ruby-oci8 1 teamcity 1 engines 1 pgadmin 1 soap 1 content_for 1 word automation 1 plugin 1 capybara 1 xml 1 bootstrap 1 migrate to rails3 1 mvc 1 unity 1 rendering 1 word2007 1 x64 1 limited stock 1 fast tests 1 pl/sql 1 delayed_job 1 pdf 1 test coverage 1 optimization 1 processing 1 borland 1 method_missing 1 cross-browser 1 devise 1 schema_plus 1 mongo 1 mongrel 1 dual boot 1 usability 1 mongrel_service 1 dba 1 mission statement 1 model 1 metadata 1 rcov 1 exceptions 1 image_tag 1 attachments 1 bde 1 css 1 yield 1 ajax 1 generative art 1 rails-assets 1 coordinate systems 1 submodules 1 netzke 1 ora-01031 1 authlogic 1 postgresql 1 shopping cart 1 agile 1 fast_tagger 1 subjective 1 wice_grid 1 generators 1 nvidia 1 mongodb 1 etsyhacks 1 staleobjecterror 1 session 1 jeweler 1 wordpress hacked 1 jasmine 1 heroku 1 rjs 1 life 1 unobtrusive-javascript 1 render_anywhere 1 html5 1 rails31 1 json 1 cocoon 1 mingw32 1 observe_field 1 osx 1 actionwebservice 1 testing 1 debugging 1 strings 1