Don’t send Javascript as an Ajax response

In this post, I’ll assume that Rails’s asset pipeline was a good choice. This debate is irrelevant to this post. If you don’t like CoffeeScript, use Javascript.

I’ve read a lot of Ruby on Rails books, including Head First Rails, Ruby on Rails Up and Running, The Rails View, and also some Brazilian authors.

All of them made the same mistake, which brought me a lot of trouble: they teached that, in order to handle an ajax response, you have to make the requested controller send back a Javascript. Some of them even told that you should use “render :update” for it! I don’t know about other authors, maybe I’m simply unlucky.

Back at those times, my controllers were awful, filled with obscure code. So a lot of more experienced programmers told me that I could create a view, like “index.js.erb”, to generate the Javascript.

Something was still wrong. I thought to myself “but wouldn’t be a lot better if I requested some data and a callback function handled this data for me? Every Ajax book I’ve seen teaches me to do this! Why should it be so difficult with Rails?”

In fact, it’s not. It’s really easy. And it makes more sense.

Why would they pack Rails with CoffeeScript, if the controller would process a “js.erb”? You can and should handle the response with a CoffeeScript callback.

How to do that? Simple enough:

$(document).ready ->
    $("a#link_id").bind "ajax:complete", (e, xhr, settings) ->
        # TODO: the callback function goes here

This will go on app/assets/javascripts/<current page’s controller’s name>.js.coffee

You can put whatever you want to identify your link (or form) instead of “a#link_id”. Of course you can define the callback function outside of the bind and pass it as a parameter.

The content of the response is inside of xhr.responseText. For example, if you requested a JSON, you can do that:

response = jQuery.parseJSON(xhr.responseText)

And you’ll have all the data from the server.

There are also other Ajax events that may help your page to have a more responsive interface:

ajax:before

ajax:loading

ajax:success

ajax:failure

ajax:complete (it is after a success OR a failure, so don’t use it instead of ajax:success)

ajax:after (after the request is sent, not after the response was processed)

But why bother with this? Won’t a Javascript response work?

Well, there are a lot of situations where a Javascript response wouldn’t work. For instance, in this page (yes, it is an awful page, but it was only a concept test).

I needed each of these submit buttons to show my data in a different way. But the data I needed would be always the same. I could use three links and update them whenever the select changed, but this would not be practical at all. This was a lot simpler:

$("#report").bind "mousedown", ->
    $("form").bind("ajax:complete", reportCallback)

$("#graph").bind "mousedown", ->
    $("form").bind("ajax:complete", graphCallback)

$("#pizza").bind "mousedown", ->
    $("form").bind("ajax:complete", pizzaCallback)

There are situations where two different pages also need the same data, but they will also process them differently. A callback function would also be the best approach for it. As a general rule, getting data and processing it with a callback function will almost always be better.

For more information on the subject, I’d recommend you to read the excelent article from John Gadbois called Using Unobtrusive JavaScript and AJAX with Rails 3

About these ads

3 thoughts on “Don’t send Javascript as an Ajax response

    • As I said here:

      “The content of the response is inside of data.responseText”

      When you make an Ajax request, you are requesting something from a controller. On the server side, you can get whatever data you want on your controller and send it as JSON or XML (that’s why you have format.json and format.xml, after all). You receive the response on data.responseText, parse it, and do whatever you want with this data on client side.

      • ah, I see. What if even if you need to update a table of a Model list, you just return a JSON structure of all that data and render via some client-side jQuery that parses that JSON…. interesting approach. Very clean. Though, certainly an approach I’d like to have started with. Would be a pain to convert to.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s