Rails 3 Remote Links and Forms:
A Definitive Guide

Also see Rails 3 Remote Links and Forms Part 2: Data-type (with jQuery).

Spoiler Alert: If you like magic, stop reading. The Rails 3 UJS driver (rails.js), which powers the remote links, forms, and inputs, is not very magical when you know how it works.

This article uses the jQuery UJS driver, though the Prototype UJS driver does the same thing. UJS, by the way, stands for “Unobtrusive JavaScript”.

If you have any experience with jQuery, take a few minutes to check out the rails.js source. It’s pretty straight forward, and only 147 lines as of this writing. I’ll be here waiting to answer your questions when you get back.


What rails.js does

  1. It finds remote links, forms, and inputs, and overrides their click events to submit to the server via AJAX.
  2. It triggers six javascript events to which you can bind callbacks to work with and manipulate the AJAX response.
  3. It handles the AJAX response from the server

What rails.js does NOT do

Notice that last bit is struck-through. This seems to be the greatest source of confusion when starting with the new Rails 3 remote functionality. Thanks to habits engrained by Rails 2′s link_to_remote and remote_form_for, we expect that Rails 3 would also handle the AJAX response for our remote links and forms. But it doesn’t; it leaves that for you.

Rails will take your luggage up to your room, but it won’t unpack your bags for you. This is by design; why would you want the bellhop going through your stuff? Also, the actual handling of the data is largely unique to each element, and depends on the data you’re working with in each case. So Rails leaves that part up to you. We’ll come back to this.

The role of HTML5

You’ve likely heard that Rails 3 uses HTML5. That’s true, but the actual role that HTML5 plays may be simpler than you suspect.

Remember the first thing rails.js does? Before it can override the click and submit events of all the remote elements, it first needs to find all the remote elements.

So, we need a way to designate our remote elements. In ancient times, we might have added class="remote" to our remote elements. But classes are for styling. Isn’t there a way to differentiate remote links that doesn’t pollute our CSS classes?

With HTML5, there is. Part of the HTML5 spec is that you can now add any arbitrary tag to an HTML element, as long as it starts with “data-”. So, this is now valid HTML5 markup:

<a href="stuff.hml" data-rocketsocks="whateva">Blast off!</a>

Rails 3 takes advantage of this new valid markup, by turning all links and forms with :remote => true into HTML elements that have the tag data-remote=true.

<%= link_to "Get remote sauce", {:action => "sauce"}, :remote => true, :class => "button-link" %>
# => <a href="sauce" class="button-link" data-remote=true>Get remote sauce</a>

And now the rails.js finds all remote links with the selectors:

$('form[data-remote]')
$('a[data-remote],input[data-remote]')

… and overrides the submit and click actions, respectively, with an ajax request to the forms’ action links’ href properties. Then it does the same thing wirh remote forms and inputs, using the form’s action.

So, that’s it, HTML5 just provides a convenient, semantic, way for us to designate and select which elements to hijack.

Handling the AJAX response

Okay, great, how the hell do we actually do something with the AJAX response? Thankfully, when rails.js sends your requests remotely, it also triggers six custom events along the way, passing the corresponding data/response to each event. You can bind your own handler functions to any of these events.

These six events are (in order):

ajax:before   // fires before the request starts, provided a URL was provided in href or action
ajax:loading  // fires after the AJAX request is created, but before it's sent
ajax:success  // fires after a response is received, provided the response was a 200 or 300 HTTP status code
ajax:failure  // fires after a response is received, if the response has a 400 or 500 HTTP status code
ajax:complete // fires after ajax:success or ajax:failure
ajax:after    // fires after the request events are finished

Update: Since this article was written, the Rails team has made some changes to the jQuery UJS driver. In the most recent versions of rails.js, there are now only 4 callback events:

ajax:beforeSend // equivalent to ajax:loading in earlier versions
ajax:success
ajax:complete
ajax:error // equivalent to ajax:failure in earlier versions

So in your page, you would bind to these events with a function like:

$('.button-link').bind('ajax:success', function(){
  alert("Success!");
});

You’ll notice that all of the Rails JavaScript functionality is facilitated by binding some function to some entity/event.

Binding is good, because it is unobtrusive. The JavaScript functionality and the HTML markup each exist as wholly separate units, which are then bound together via JavaScript. If the user has no JavaScript, then the JavaScript that binds the JS functions to the HTML entities is never executed, and the user is left with only clean, valid HTML.

Putting it all together

Enough explanation, let’s create a remote form that loads some content into the page. We’ll provide the user with instant feedback, fully handle any errors, and reset the form so they can do it again. Armed with the knowledge above, hopefully none of the following will seem like magic.

The following assumes we have a Comment model in our Rails app, which contains a “content” text column in the database. We will allow a user to create a comment, by submitting the form remotely, and then insert the comment into the page.

You’ll notice we’re requesting an HTML response directly, but then returning errors in JSON. We’re also overriding much of the magic provided by respond_with. This is all to illustrate how much control we have over the request/response.

See the follow-up post describing how to request a JS (or XML or JSON or text or whatever) response, and with a more production-appropriate example.

View

<%= form_for @comment, :remote => true, :html => { :'data-type' => 'html', :id => 'create_comment_form' } do |f| %>
  <%= f.text_area(:content) %>
  <div class="validation-error"></div>
  <%= f.submit %>
<% end %>

<div id="comments"></div>

Controller

respond_to :html, :xml, :json
...

def create
  @comment = Comment.new( params[:comment] )

  if @comment.save
    respond_with do |format|
      format.html do
        if request.xhr?
          render :partial => "comments/show", :locals => { :comment => @comment }, :layout => false, :status => :created
        else
          redirect_to @comment
        end
      end
    end
  else
    respond_with do |format|
      format.html do
        if request.xhr?
          render :json => @comment.errors, :status => :unprocessable_entity
        else
          render :action => :new, :status => :unprocessable_entity
        end
      end
    end
  end
end

Obviously, we would have a _show.html.erb partial view, which would be our template for displaying the comment. Hopefully you know how to do that.

At this point, we have a form that remotely submits to our server, and our server responds with our view partial, ready to be inserted into the page. Just one thing… it’s not actually being inserted into the page.

JavaScript

It’s time to bind some handler functions to those triggered “ajax” events. So, in the page that has our form, we’ll want to include this javascript (probably in the <head> section or in a separate js file).

Update: The following has been updated to bind to the callbacks available in the most recent versions of rails.js.

$(document).ready(function(){

  $('#create_comment_form')
    .bind("ajax:beforeSend", function(evt, xhr, settings){
      var $submitButton = $(this).find('input[name="commit"]');

      // Update the text of the submit button to let the user know stuff is happening.
      // But first, store the original text of the submit button, so it can be restored when the request is finished.
      $submitButton.data( 'origText', $(this).text() );
      $submitButton.text( "Submitting..." );

    })
    .bind("ajax:success", function(evt, data, status, xhr){
      var $form = $(this);

      // Reset fields and any validation errors, so form can be used again, but leave hidden_field values intact.
      $form.find('textarea,input[type="text"],input[type="file"]').val("");
      $form.find('div.validation-error').empty();

      // Insert response partial into page below the form.
      $('#comments').append(xhr.responseText);

    })
    .bind('ajax:complete', function(evt, xhr, status){
      var $submitButton = $(this).find('input[name="commit"]');

      // Restore the original submit button text
      $submitButton.text( $(this).data('origText') );
    })
    .bind("ajax:error", function(evt, xhr, status, error){
      var $form = $(this),
          errors,
          errorText;

      try {
        // Populate errorText with the comment errors
        errors = $.parseJSON(xhr.responseText);
      } catch(err) {
        // If the responseText is not valid JSON (like if a 500 exception was thrown), populate errors with a generic error message.
        errors = {message: "Please reload the page and try again"};
      }

      // Build an unordered list from the list of errors
      errorText = "There were errors with the submission: \n<ul>";

      for ( error in errors ) {
        errorText += "<li>" + error + ': ' + errors[error] + "</li> ";
      }

      errorText += "</ul>";

      // Insert error list into form
      $form.find('div.validation-error').html(errorText);
    });

});

Each of these functions could easily be abstracted, so that they can be easily or automatically applied to all of our remote forms.

These bindings also work the same way with remote links, but I figured we’d use a remote form for this example, since it requires a couple extra steps that aren’t immediately obvious (like clearing the form or populating validation errors).

Also, note that the data passed to your functions from the ajax events are not in the same order. We have evt, data, status, xhr for ajax:success, and evt, xhr, status, error for ajax:failure. This will get ya every time.

But wait, there’s more

If you did your homework at the beginning of the article, and looked at the rails.js file, you would have noticed a couple additional details.

.live()

Instead of directly binding to the click events of remote links, forms, and inputs, rails.js actually uses .live(). Likewise, in the javascript above, you could replace .bind() with .live() to be a bit more versatile.

See Exploring jQuery .live() and .die() and The Difference Between jQuery’s .bind(), .live(), and .delegate() for more info.

Update: If you’re going to use .live() to live-bind your AJAX handlers, be sure you’re on the latest jQuery (> v1.4.4), because there are issues with v1.4.2 in IE.

:confirm => “Are you sure?”

You’ll also notice that the rails.js file handles :confirm => "Are you sure?" as well (which will pop up a box that says “Are you sure?” when you click or submit something (you can also just pass in :confirm => true for the default message)). Just like the remote functionality, Rails 3 simply adds the HTML5-valid tag data-confirm=true to your HTML elements.

:disable_with => “Submitting…”

Rails 3 gives us another option called, :disable_with, that we can give to form input elements to disable and re-label them while a remote form is being submitted. This adds a data-disable-with tag to those inputs, to which rails.js can select and bind this functionality.

This could be used in place of our ajax:loading and ajax:complete bindings in the example above. But then I’d need to come up with something else for those bindings to do, to show how they work.

To see how to get remote links and forms working with js.erb (or any other format for that matter), check out Part 2 to this article.

Additional Resources

By some stroke of temporary sanity, I actually wrote down the links I came across when I first tackled Rails 3 remote functionality.

If you’re itching for more information, check out these resources (and for crying out loud, go read the source code already!). In no particular order:

43 Responses to “Rails 3 Remote Links and Forms:
A Definitive Guide”

  1. Juanma says:

    Hello Steve.
    I have found your article very well written and very good for teaching how to make ajax applications with Rails 3.0
    But there is something that strikes me on my mind since I saw this in the first time, and it is that with format.js respond_to should give a response of javascript (you could even use a template file create.js.erb and it would be javascript), but in the sample the response is an html partial.
    I always have had the feeling of not doing the most correct code when doing things like this.
    I would like to know your opinion about this.
    Thank you.
    Juanma

  2. Hey Juanma, that is a valid point, but I think it simply comes down to personal preference. The simple fact is you control the response and you control the response handling, so you can do whatever you want.

    In this particular example, think about what our js.erb would actually say. It would most likely be a one-line file with something like:

    $('#comments').append('escape_javscript(< %= render :partial => 'show', :locals => {:comment => @comment} %>');

    And then, in our view, we’d still need something like:

    $('#create_comment_form')
        .bind("ajax:success", function(evt, data, status, xhr){
            eval(xhr.responseText);
        });

    I dunno, I guess it just seems like a lot of unnecessary moving parts. But again, I think it simply comes down to personal preference. I’d be interested to hear what others’ thoughts are on this.

  3. solnic says:

    @Juanma That’s a good point and I also find it as a common mistake in rails apps. What people usually do is to send an ajax call with accept header set to text/javascript even though they’re going to respond with an html. The correct way of doing this is to set accept header to text/html and in the action render correct template depending on whether it was an XHR request or not. For instance you could write:

    respond_to do |wants|
      wants.html do
        if request.xhr?
          render :partial => "items"
        else
          render
        end
      end
    end

    If rails UJS drivers generate ajax calls with accept headers set always to text/javascript and there’s no way of changing that then…well, they kinda suck again.

  4. Also, to elaborate on the point I was making, think about what’s actually happening when you respond with the view partial vs. responding with the js.erb.

    What is the js.erb actually doing? It’s rendering the entire text of your view partial, but then wrapping it in a bit of javascript and returning the whole thing as a string. And then your page has to take that string and execute it as javascript in order to extract your HTML from the view partial back out.

    So, the only real difference in responding with the HTML from the view partial, is that it doesn’t wrap the HTML in a javascript function which must then be unwrapped with the your javascript response handler.

    @Solnic, yes I agree, ideally we’d properly set our request header accordingly, no matter which method we choose. And the jQuery rails.js UJS driver uses jQuery’s standard $.ajax() command.

  5. Rohan Dey says:

    Great article … I never bothered to know how many lines where there is rails.js but impressed with 147 lines.

  6. Włodek Bzyl says:

    There is an error in the line below:

    true, :id => “create_comment_form” do |f| %>

    The `:id` should be wrapped with `:html => {}`:

    true, :html => {:id => “create_comment_form”} do |f| %>

  7. I have an issue with remote links (:remote => true):
    The respond consists of html + javascript. The problem is that the javascript is just rendered by the browser but not performed.

    Any ideas?

  8. Rami, I don’t know if it helps your specific issue, but see my earlier comment in response to Juanma for getting the javascript response to execute.

  9. Petrov says:

    Schwartz, thanks for the tutorial!
    I’m a Rails newbie. Before your tutorial I did a similar one where they talked about full create/update/delete with ajax (http://www.stjhimy.com/posts/7), however they use the js.erb files.
    Is it possible that you make a second post on how to do CRUD with you technique?

  10. Brian says:

    Thanks for this post! Great stuff…however, i’m really needing the ability to set the response (html/JSON/etc). I’m comfortable enough with jQuery to just edit the rails.js file, but i’m assuming there’s a better approach?

  11. Brian says:

    Doh! nevermind…I just spent some more time mucking around in the source. setting data-type=”JSON” on the element seems to be the solution….

  12. @Brian and Petrov: Thanks for the feedback! I’ve been getting a lot of comments/questions about this exact point, so I’m writing a follow-up article delving into custom data-type responses, including JS with js.erb, html, JSON, etc. I’m hoping to have it published by next week. Stay tuned ;-)

  13. Brian says:

    @Steve, just came across an issue that you might be able to address. I sometimes “disable” links that make async requests. In switching to the rails.js library, i’m finding it difficult to do that since it pretty much takes over. The only solution i can think of is to unbind “click.rails”…is there a better solution?

  14. [...] how we make that happen. Let’s assume our JavaScript is set up similarly to the code in Rails 3 Remote Links and Forms: A Definitive Guide. First, let’s add a function to our jQuery arsenal, called .turnRemoteToToggle. You can put [...]

  15. [...] work for any jQuery plugins using AJAX requests (e.g. lightbox plugins, etc.), as well as for all Rails 3 remote links and forms (provided we’re using the jQuery UJS driver). In the page layout or in an included js file, [...]

  16. David says:

    Congratulations for this guide. There are few ressources about this way of doing unobtrusive JS in Rails 3, and I was losing hope before coming here. I will follow your blog closely.

  17. [...] Continued from Rails 3 Remote Links and Forms: A Definitive Guide. [...]

  18. BServiss says:

    Updating a Rails 2.3 project taught me one thing – javascript is ugly! Look at the code for the js bindings, one might as well use Erlang. I don’t mean any offense, but Ruby and Rails idiom makes a lot of sense to me and adding this javacrap(tm) is not only a waste of time but degrades the whole app.

    Another thing I learned was that, many times, the special effects were an unnecessary complication for the page.

  19. BServiss, I rather like JavaScript. But I know a lot of people who agree with you. Have you checked out CoffeeScript? It has great support for Rails and I know some developers who swear by it.

  20. Nick Boyce says:

    Great article, thanks.

    Small typo at the start where you introduce the jQuery callbacks. ajax:sucess should be ajax:success

  21. RobR says:

    Hi Steve,
    Perhaps you could figure this out. If I leave out :remote from the following, params has a hash with the file passed to it. If I include :remote => true, I get absolutely nothing. If I put in a text_field, works fine in both cases. Any thought?

    <%= form_tag "upload_data", :multipart => true, :remote => true do  %>
    <%= file_field 'tempfile', 'file' %>
    <%= submit_tag 'Load Data' %>
    <% end %>
  22. RobR: Yes, the problem is that JS will not let you upload a file via xhr, because it’s considered a security risk. Plugins like jquery.form.js get around this by creating an iframe, copying the form over, and submitting it normal-style from the iframe.

    I recommend the Remotipart gem, which automatically integrates with Rails 3 and the jquery-ujs and form.js to handle file ajax file uploads for you.

    The only problem is that the Remotipart gem does not yet work with the latest jquery-ujs. The good news is I have a patch for both the jquery-ujs and the Remotipart gem which make them work together. See here for instructions to get it working.

  23. Techism says:

    First off, GREAT post. You really helped me connect the dots here on how ajax is going to work for me in my new app built on Rails 3x and jQuery.

    However, I’m a little confused here. I followed these steps but many little details seem off: validation errors are rendering as success (and being dumped as a string into the “show” div). The submit button text isn’t being changed…even though the binding is being triggered.

    # billables_controller.rb
    def create
         @billable = Billable.new(params[:billable])
         if @billable.save
           respond_with( @billable, :status => :created, :location => @billable ) do |format|
             format.html do
               if request.xhr?
                 render :partial => "billables/show", :locals => { :billable => @billable }, :layout => false
               else
                 redirect_to(billables_url, :notice => 'Billable was successfully created.')
               end
             end
           end
         else
           respond_with( @billable.errors, :status => :unprocessable_entity ) do |format|
             format.html do
               if request.xhr?
                 render :json => @billable.errors
               else
                 render :action => :new
               end
             end
           end
         end
       end
    $(document).ready(function(){

        $('#create_billable_form')
            .bind("ajax:beforeSend", function(evt, xhr, settings){
              var $submitButton = $(this).find('input[name="commit"]');
              // Update the text of the submit button to let the user know stuff is happening.
              // But first, store the original text of the submit button, so it can be restored when the request is finished.
              $submitButton.data( 'origText', $(this).text() );
              $submitButton.text( "Submitting..." );
           
            })
            .bind("ajax:success", function(evt, data, status, xhr){
              var $form = $(this);

              // Reset fields and any validation errors, so form can be used again, but leave hidden_field values intact.
              $form.find('textarea,input[type="text"],input[type="file"]').val("");
              $form.find('div.validation-error').empty();

              // Insert response partial into page below the form.
              $('#billables').append(xhr.responseText);

            })
            .bind('ajax:complete', function(evt, xhr, status){
              var $submitButton = $(this).find('input[name="commit"]');

              // Restore the original submit button text
              $submitButton.text( $(this).data('origText') );
            })
            .bind("ajax:error", function(evt, xhr, status, error){
              var $form = $(this),
                  errors,
                  errorText;

              try {
                // Populate errorText with the comment errors
                errors = $.parseJSON(xhr.responseText);
              } catch(err) {
                // If the responseText is not valid JSON (like if a 500 exception was thrown), populate errors with a generic error message.
                errors = {message: "Please reload the page and try again"};
              }

              // Build an unordered list from the list of errors
              errorText = "There were errors with the submission: \n<ul>";

              for ( error in errors ) {
                errorText += "<li>" + error + ': ' + errors[error] + "</li> ";
              }

              errorText += "</ul>";

              // Insert error list into form
              $form.find('div.validation-error').html(errorText);
            });

        });

    Tried using jQuery v1.5.1, then though maybe I should roll back a few versions and tried with v1.4.4

    Rails v3.0.4

    • Techism says:

      I got mine working more like your example when I went back to good old render for the validation errors:

      def create
           @billable = Billable.new(params[:billable])
           @billable.user_id = current_user.id
               
           if @billable.save
             respond_with( @billable, :status => :created, :location => @billable ) do |format|
               format.html do
                 if request.xhr?
                   render :partial => "billables/show", :locals => { :billable => @billable }, :layout => false
                 else
                   redirect_to(billables_url, :notice => 'Billable was successfully created.')
                 end
               end
             end
           else
             respond_to do |format|
               format.html {
                 if request.xhr?
                   render :json => @billable.errors, :status => :unprocessable_entity
                 else
                    render :action => :new
                 end
               }
             end
           end
         end

      An interesting side-note…while it was returning as 200, I went a ways embracing that and had something QUITE like the old form_for_remote functionality going with it re-rendering the form, populating it, and highlighting validation errors nicely from the same partial. I strongly favor leaning on rails to do that bit rather than letting JS plug in the validation errors and all that rot. The only hitch was that I couldn’t figure out how to re-ajaxify the newly rendered form. I poked around in rails.js, but couldn’t quite get my head around how I could invoke the action that ajaxifies the form with data-remote on it, but if I could, then it would have been easy to add after the ajax render in my js.

      This would be technically correct too since technically a validation error response is a 200, successful interaction from the server…Then we let rails magic handle the rest…less code required and conventional consistency in validation interactions with the user. *IF* I could only get a form inserted via ajax to to pick up the hook rails.js adds on load.

    • Techism says:

      One last update: I figured out where my problem seems to have been rooted and got back to the nice respond_with code. It just seems that the status param isn’t being picked up by the json render, so you just have to specify it again. Is this a mistake in the tutorial?

      Here’s my latest create method:

      def create
           @billable = Billable.new(params[:billable])
           @billable.user_id = current_user.id
           if @billable.save
             respond_with( @billable, :status => :created, :location => @billable ) do |format|
               format.html do
                 if request.xhr?
                   render :partial => "billables/show", :locals => { :billable => @billable }, :layout => false
                 else
                   redirect_to(billables_url, :notice => 'Billable was successfully created.')
                 end
               end
             end
             else
              respond_with( @billable.errors, :status => :unprocessable_entity ) do |format|
                format.html do
                  if request.xhr?
                    render :json => @billable.errors, :status => :unprocessable_entity
                  else
                    render :action => :new
                  end
                end
              end
            end
          end
      • Hey Techism, sorry about the confusion. That was a mistake in the article, good catch. The problem was that when we do format.html { ... } inside the respond_with block, we’re actually overriding the respond_with parameters for that format’s response. So, we need to re-specify our respond_with options. I’ve updated the article with the proper code.

        However, I should emphasize that the extensive example in this article, with all the overriding of the standard formats and options, was really meant to show how much you could customize the ajax response handling. 80% of the time, we probably would not need to mess with the rails defaults this much. I highly recommend reading part 2 of this article for a better explanation, and for a much more production-ready example.

        Concerning your questions about getting the newly inserted form to be “ajaxified”, check out my other article that explains how .live() works, which is the method rails.js uses to attach the ajax handlers to forms and links.

    • I investigated a little more and realized that my code here was using a really old version of the Rails Responder. Rails 3 actually uses a newer controller responder, where :status and :layout are already inferred from the action. We only need to specify them inside the format blocks, which are overriding the default respond_with options. I’ve updated the article with the proper rails responder code.

      I’m really surprised no one had caught this snafu earlier. Thank you very much for the heads up and making me double check my work! ;-)

      • Techism says:

        Hey, my pleasure. To my knowledge this is the ONLY reference on the web for rails 3 ajax that makes a lick of sense. Thank YOU.

        I’m sure you’ve not heard the last of me as I proceed in my attempts to build a custom calendar-oriented interface for managing many different assets in one place.

        For example, now that I’ve added my billable, I can pass the show partial to my list of billable for that date, but how to also add a different partial for the same object to the calendar cell with id “mm-dd-yyyy” = billable.date?

        (current theory: render a js.erb that somehow pulls and parses the two partials and then pushes to correct divs? Or do I use a sub-method in controller to update the cal div?)

        Finding out is going to be fun :D

        PS: thanks for the tips on part 2 and live functions. I had read these, but I’m learning kinda procedurally here. I liked the argument above about returning html actually making sense because converting it to json, which then coverts it back to html is silly.

      • Thanks, that means a lot!

        I’m not totally sure I understand you’re example, but you’d probably want a js.erb as you pointed out, that does something like:

        $('#list').append('< %= escape_javascript(render :partial => 'blah') %>');
        $('#calendar').find('#day').append('< %= escape_javascript(render :partial => 'other_blah') %>');
  24. Jims says:

    Hi! thanks for writing this post.
    I wrote _show.html.erb partial but as soon as I posted a new comment,
    the @comment.content in _show.html.erb doesn’t show.

    1) where do we call _show.html.erb?
    2) the data that’s rendered and returned after a save has been done – is that @comment.content or comment.content?

  25. Kevin says:

    Corrrect me if Im wrong but should $submitButton.text( “Submitting…” ); be $submitButton.val( “Submitting…” ); ? The .text() is referenced a couple other places too

    • It depends on the actual element you’re using; it’d be text() if it was a button element, and val() if it’s an input element. So yes, given the example in this article, it should be val().

  26. railsguy says:

    if I have multiple forms for nested attributes belonging to the same controller, Ihow can I identify the coreect sending form in the controller in order to render the correct partial?

    E.g., I have a ajax form to add an answer to a question and another ajax form to add a comment to a answer, with comment being a nested attribute of answer. How can I identify whether to render an answer or a comment in the controller “respond to” function?

    • There are a couple different ways you could do that. You could put logic in your template to render one partial or another based on whether it was an answer or comment. You could also do it directly in your template.

      respond_to do |format|
        format.js { render :template => (params[:question][:answer] ? :answer_template : :comment_template) }
      end
  27. I’m newbie for RoR(Migrated from PHP), I was searching for Ajax, I got it here, Thanks a Lot,

  28. Dab says:

    This article is solid gold.
    But for 1.7+ Jquery, should you be using .on() instead?

  29. reggieb says:

    Doesn’t an ajax error mean that the client was unable to complete the call to the server. Therefore, handling the error by outputting response text is not the right solution. Instead shouldn’t you process the ajax error or status object.

    Also I think ajax:error object only passes three parameters to the function: error(jqXHR, textStatus, errorThrown).

    Therefore this section:

      .bind('ajax:error', function(evt, xhr, status, error){

        // Display the errors (i.e. an error partial or helper)
        $(this).find('.errors').html(xhr.responseText);

      });

    Should be something like:

      .bind('ajax:error', function(xhr, status, error){

        // Display the errors (i.e. an error partial or helper)
        $(this).find('.errors').html(status);

      });
    • That’s a good point, but it really just depends on your app. jQuery will actually fire the error event if your server responds with a 4xx or 5xx status code as well. For most of my apps, the vast majority of errors from the app are from the back end and come with explanations, like validation failures (422 Unprocessable Entity) when trying to save an object.

Leave a Reply

You may include code snippets in your comment using this syntax.