Usually when it comes to customizing JSON objects we use as_json, i.e., if we want to show a post and include its author and comments, we can set up a JSON response as follows:
def show
@post = Post.find(params[:id])
respond_to do |format|
format.html
format.json { render json: @post.as_json( only: [ :id, :name, :content ],
include: [ :author, { comments: {
only: [ :id, :name, :content ]} }] )}
end
end
Yep, this works, but depending on the customization that we want for the JSON object, this code could turn very ugly.
So what would I suggest? Well, using the Jbuilder gem is a good call. You can find it all ready added in your Gemfile (if using Rails 3.2 or later, if not, just add it to your Gemfile), you only need to uncomment the line and run Bundle.
# To use Jbuilder templates for JSON
# gem 'jbuilder'
You can either use Jbuilder stand-alone or directly as an ActionView template language. When required in Rails, you can create views à-la show.json.jbuilder (the json is already yielded)
For example, you can use Jbuilder to override the to_json or as_json methods on your models or presenters.
def to_json
Jbuilder.encode do |json|
json.(self, :id, :name, :content)
json.author(self.author, :name)
json.comments(self.comments, :id, :name, :content)
end
end
And now your controller action would look (so much better) like this:
def show
@post = Post.find(params[:id])
end
Also can use Jbuilder as templates, i.e
#app/views/posts/show.json.jbuilder
json.(@post, :id, :name, :published_at)
json.author(@post.author, :id, :name)
json.comments(@post.comments, :id, :name, :content)
We can even use partials on those templates:
#/app/views/comments/_comment.json.jbuilder
#...
json.comments @post.comments do |json, comment|
json.partial! comment
end
So there you have it, an easy and cleaner way to handle your custom JSONs objects. Do you have another way to do it? If so, we would like to know your tips and tricks.