How to customize to_json response in Rails 3

coneybeare picture coneybeare · Sep 15, 2010 · Viewed 14k times · Source

I am using respond_with and everything is hooked up right to get data correctly. I want to customize the returned json, xml and foobar formats in a DRY way, but I cannot figure out how to do so using the limited :only and :include. These are great when the data is simple, but with complex finds, they fall short of what I want.

Lets say I have a post which has_many images

def show
  @post = Post.find params[:id]
  respond_with(@post)
end

I want to include the images with the response so I could do this:

def show
  @post = Post.find params[:id]
  respond_with(@post, :include => :images)
end

but I dont really want to send the entire image object along, just the url. In addition to this, I really want to be able to do something like this as well (pseudocode):

def show
  @post = Post.find params[:id]
  respond_with(@post, :include => { :foo => @posts.each.really_cool_method } )
end

def index
  @post = Post.find params[:id]
  respond_with(@post, :include => { :foo => @post.really_cool_method } )
end

… but all in a DRY way. In older rails projects, I have used XML builders to customize the output, but replicating it across json, xml, html whatever doesnt seem right. I have to imagine that the rails gurus put something in Rails 3 that I am not realizing for this type of behavior. Ideas?

Answer

PerfectlyNormal picture PerfectlyNormal · Jan 26, 2011

You can override as_json in your model. Something like:

class Post < ActiveRecord::Base
  def as_json(options = {})
    {
      attribute: self.attribute, # and so on for all you want to include
      images:    self.images,    # then do the same `as_json` method for Image
      foo:       self.really_cool_method
    }
  end
end

And Rails takes care of the rest when using respond_with. not entirely sure what options gets set to, but probably the options you give to respond_with (:include, :only and so on)