[ruby-on-rails] Rendering JSON in controller

I was reading a book and in a chapter about Controllers when it talks about rendering stuff, for JSON it has an example like this but doesn't go in to details so I couldn't figure out the bigger picture that this example fits in:

render :json => @projects, :include => tasks

And also some example with JSONP using it with callback functions:

render :json => @record, :callback => 'updateRecordDisplay'

Can someone explain these?

This question is related to ruby-on-rails json ruby-on-rails-3.2

The answer is


What exactly do you want to know? ActiveRecord has methods that serialize records into JSON. For instance, open up your rails console and enter ModelName.all.to_json and you will see JSON output. render :json essentially calls to_json and returns the result to the browser with the correct headers. This is useful for AJAX calls in JavaScript where you want to return JavaScript objects to use. Additionally, you can use the callback option to specify the name of the callback you would like to call via JSONP.

For instance, lets say we have a User model that looks like this: {name: 'Max', email:' [email protected]'}

We also have a controller that looks like this:

class UsersController < ApplicationController
    def show
        @user = User.find(params[:id])
        render json: @user
    end
end

Now, if we do an AJAX call using jQuery like this:

$.ajax({
    type: "GET",
    url: "/users/5",
    dataType: "json",
    success: function(data){
        alert(data.name) // Will alert Max
    }        
});

As you can see, we managed to get the User with id 5 from our rails app and use it in our JavaScript code because it was returned as a JSON object. The callback option just calls a JavaScript function of the named passed with the JSON object as the first and only argument.

To give an example of the callback option, take a look at the following:

class UsersController < ApplicationController
    def show
        @user = User.find(params[:id])
        render json: @user, callback: "testFunction"
    end
end

Now we can crate a JSONP request as follows:

function testFunction(data) {
    alert(data.name); // Will alert Max
};

var script = document.createElement("script");
script.src = "/users/5";

document.getElementsByTagName("head")[0].appendChild(script);

The motivation for using such a callback is typically to circumvent the browser protections that limit cross origin resource sharing (CORS). JSONP isn't used that much anymore, however, because other techniques exist for circumventing CORS that are safer and easier.


For the instance of

render :json => @projects, :include => :tasks

You are stating that you want to render @projects as JSON, and include the association tasks on the Project model in the exported data.

For the instance of

render :json => @projects, :callback => 'updateRecordDisplay'

You are stating that you want to render @projects as JSON, and wrap that data in a javascript call that will render somewhat like:

updateRecordDisplay({'projects' => []})

This allows the data to be sent to the parent window and bypass cross-site forgery issues.