Ajax on Rails

Jul 1, 2013

I'm trying to teach to some good friends a little bit about web development in Rails. To do this I have to explain from scratch to them about AJAX technique, here is the document used as guide to do this

AJAX (Asynchronous JavaScript and XML)

It's a technique used in client side to send data and retrive responses in asynchronic way.

Different technologies interact to carry out AJAX

  • HTML and CSS for presentation
  • The Document Object Model (DOM) for interaction with data
  • XML for the interchange of data (JSON, HTML, TEXT)
  • The XMLHttpRequest object for asynchronous communication
  • JavaScript to bring these technologies together

XMLHttpRequest (XHR)

This is an OBJECT available in web browser scripting languages. This object was created by microsoft and standarized by w3c here.

It is used to send HTTP or HTTPS (another protocols too) requests directly to a web server and load the server response data directly back into the script.

This object is governed by a rule named "same origin policy"

All modern browsers (IE7+, Firefox, Chrome, Safari, and Opera) have a built-in XMLHttpRequest object.

xmlhttp = new XMLHttpRequest();
      
Mozilla example page.

Javascirpt wrap to XMLHttpRequest object?

Javascript (the browser language) is able to create this kind of object of course, in particular JQuery library can create this kind of object, for example:

$.ajax( [settings ] )

// Assign handlers immediately after making the request,
// and remember the jqxhr object for this request
var jqxhr = $.ajax( "example.php" )
    .done(function() { alert("success"); })
    .fail(function() { alert("error"); })
    .always(function() { alert("complete"); });

// perform other work here ...
// Set another completion function for the request above
jqxhr.always(function() { alert("second complete"); });
      

Rails

Rails use jquery library preferentially using jquery-rails gem.

Is very easy dig into this file to discover all the magic to get Ajax working in a rails project, for example here is the line where a remote call is managed.

(inspect and show a little more about this file, for example show how this file respond with events as ajax:success, ajax:complete, ajax:failure, etc)

Note: The dataType parameter passed to this method is used to populate the Accept Header in the HTML Request. (http://www.w3.org/Protocols/HTTP/HTRQ_Headers.html#z3)

There are several combinations that you can use to get Ajax working in a rails project, here we will resume them

  1. First the basic, most used, respond with a js.erb files
    # views/articles/index.html.haml
      = div_for @article do
        %div{class="details"}
        = link_to 'Show Full Article', @article, remote: true
    
    # Request
      Processing by ArticlesController#show as JS
      ...
    
    # Process
      def show
        @article = Article.find(params[:id])
    
        respond_to do |format|
            format.js {}
        end
      end
    
    # Response
      # /app/views/articles/show.js.erb
      $('#<%= dom_id(@article) %> .details').html('<%= escape_javascript render("show") %>');
    
    # /app/views/articles/_show.js.erb
      Title: <%= @article.title %>
      Body: <%= @article.body %>
                

    Pro/Con

    Server is returning js, some developers prefer do all js from client side always erb ???

  2. Json response from server and manage the presentation from client
    # View
    = div_for @article do
      %div{class="details"}
      = link_to 'Show Full Article', @article, remote: true, "data-type" => :json
    
    # Request
    Processing by ArticlesController#show as JSON
    
    # Process & Response with @article.json data
    def show
      @article = Article.find(params[:id])
    
      respond_to do |format|
        format.json { render :json =>  @article }
      end
    end
    
    # Manage the response
    # app/assets/javascripts/articles.js
    $(function($) {
    
        // Callback for rendering via JSON
        $('.article a[data-type=json]').on('ajax:success', function(event, data, status, xhr) {
            $(this).parents('div.article').find('.details').html('< div > Title: ' + data.title + '< / div >' +'< div >Body: ' + data.body + '< / div >');
        });
    });
                

    Pro/Con

    Returning JSON leads to a clean server-side API, but as you can see in the above example, taking the JSON data and then turning it into HTML can get a bit ugly

  3. Render html in server side and present it using client side
    # Request
    = link_to 'Show Full Article', @article, :remote => true, "data-type" => :html
    
    # Process and response
    def show
        @article = Article.find(params[:id])
    
        respond_to do |format|
            format.html { render :layout => ! request.xhr? }
                render :partial => 'chiquito', layout: false
        end
    end
    
    # app/views/article/show.html.haml
      "#{@article.title}"
      = render 'article'
    
    # app/views/articles/_article.html.haml
    . . .
    
    # Manage Response
    $(function($) {
      // Callback for rendering via HTML
      $('.article a[data-type=html]').on('ajax:success', function(event, data, status, xhr) {
        $(this).parents('div.article').find('.details').html(data);
      });
    });