Ruby on Rails Advanced JSON Serialization

35,806

Solution 1

You hint at the solution in your question. You most likely want to build up a hash to render to JSON. The preferred way of doing this now is by providing an implementation for the as_json method. as_json provides a formal means of customizing to_json output by building up a hash containing the data you wish to encode.

A more thorough treatment of how as_json and to_json interact can be found on Jonathan Julian's weblog.

Solution 2

You should be able to nest the :include, :except, etc. like so:

:except => {:item => [ :created_at, :updated_at, :draft, :id, :publish ]}...

If that doesn't work, make it an object (e.g. an OpenStruct) instead of a hash.

-- Markus

Solution 3

to_json has a :method option that includes the result of any method you name, you could define a method on that model that returns the additional data you want in your JSON.

Solution 4

(Please accept an answer)

I think that the link that nirvdrum gave holds your answer. I only answer because nobody has mentioned encode_json.

In your case you should only be dealing with as_json. Either by building a hash (with various calls to as_json) and sending that to render :json => ... (without the call to to_json) or by simply implementing as_json on your model and letting rails do all the work. (But I suspect you'll need the former.)

If you really need some fancy js in your rendered response then you can implement encode_json in your classes (again, not to_json). For example:

class JsEmptyClosure
  def encode_json(*args)
    "jQuery[\"noop\"] || function(){}"
  end
  def as_json(*args) self end
end

This will now respond to to_json with valid js (but note it's not actually json).

Share:
35,806
Admin
Author by

Admin

Updated on July 09, 2022

Comments

  • Admin
    Admin almost 2 years

    I'm looking to render an index of all articles along with a full article via JSON in my rails app, but I'm having a little trouble figuring out how to do it.

    Here is my controller now:

    if params[:id]
        @article = Article.find(params[:id])
    else
        @article = Article.published.not_draft.by_recent.first
    end
    
    respond_to do |format|
    
    format.js { render :json => @article.to_json(
    :except => [ :created_at, :updated_at, :draft, :id, :publish ], 
    :include => {
        :comments => {
            :only => [:body]
        }
    }),
    :callback => params[:callback]}
    end
    

    What I'd like to do in the response is add an index of all articles, like so:

    @index = Article.find(:all, :select => 'id, title')
    

    The only way I've been able to do it, is put both the index and article into a hash or array and then put that to JSON.

    @response = { :item => @article, :index => @index }
    

    Full code with both:

    @index = Article.find(:all, :select => 'id, title')
    
    if params[:id]
        @article = Article.find(params[:id])
    else
        @article = Article.published.not_draft.by_recent.first
    end
    
    @response = { :item => @article, :index => @index }
    
    respond_to do |format|
    
    format.js { render :json => @response.to_json(), :callback => params[:callback]}
    
    end
    

    This would be fine, except now I cannot specify :include or :except and get it to render properly.