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:

    link_to_remote "Add to cart",
      :url => { :action => "add", :id => product.id },
      :update => { :success => "cart", :failure => "error" }

(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:

    link_to "Add to cart", :url => {:action => "add", :id => product.id},  :remote => true

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) :

    $('.cart').replaceWith(<%= escape_javascript(render :partial => 'cart') %>)

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 :

    <% form_remote_tag :url => { :action => 'run' },
            :id => "tool-form",
            :update => { :success => "response", :failure => "error" },
            :loading => "$('#loading').toggle()", :complete => "$('#loading').toggle()" %>

That translates to this in Rails3 :

    <% form_tag url_for(:action => "run"), :id => "tool-form", :remote => true do %>

and inside some javascript (application.js), you bind the events

    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);
        });
    });

For completeness, here is a list of the events and their expected parameters:

 .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) {})

[UPDATED 7/2/2012] Updated to reflect the new event-names. :loading was renamed to :beforeSend, and :failure was renamed to :error.