How to customize the to_json method in rails3?
I want to convert an array of Place objects to json, I've been doing it like this:
var places = <%= @places.to_json.html_safe %>;
The only problem is that every place in the @places array has an associated tag list that doesn't get included. I'm using the acts_as_taggable_on gem to handle tags, so to get the tag list for a place I need to say place.tag_list.
What do I have to do to get the tag_list included for each place in the javascript array? I t开发者_如何学JAVAhink I'll need to write my own to_json method but I don't know how.
EDIT
It turns out that this is easier than I realized. I was able to say this:
var places = <%= @places.to_json(:include => :tags).html_safe %>
The only problem is that this includes more information about each tag than I really need. Every tag has an id and name, what I really want is just a list with tag names in it.
The to_json
method also accepts an argument called methods
. This argument allows you to specify methods that should be called and included in the json representation of the object. Since you mentioned that you have a method called tag_list
, you can do this:
var places = <%= @places.to_json(:methods => :tag_list).html_safe %>
If, for some reason, you don't have a method to produce tag names, but each tag has a method to give you its name, you could add a method inside your Place
model to produce a list of tag names like so:
def tag_names
tags.collect do |tag|
tag.name
end
end
Then you could get your places json with tag_names
like this:
place_json = @places.to_json(:methods => :tag_names)
This technique will work for any computed attributes you'd like to add to a model's json representation.
Within your Place class, you can override to_json. In Rails 3, you should override as_json instead:
def as_json (options={})
# add whatever fields you need here
end
Then change your code to:
var places = <%= @places.as_json.html_safe %>;
Benson's answer will not work if you are calling
render :json => @places
in the PlacesController. You will need to add the following code in the Place model.
# this method is called on a single instance
def to_json(options={})
options[:methods] ||= []
options[:methods] << :tag_names
super(options)
end
# this method is called for each instance in an Array to avoid circular references.
def as_json(options={})
options[:methods] ||= []
options[:methods] << :tag_names
super(options)
end
Hope that helps someone else. I had to look through the source code to figure out why Array.to_json
is not the same as Array.each { |a| a.to_json }
I would recommend checking out this post if you are doing more complex JSON.
How to override to_json in Rails?
See those two posts as well:
http://www.tonyamoyal.com/2011/03/25/recursive-custom-to_json-in-ruby-for-arrays-of-objects-or-nested-objects/
http://jonathanjulian.com/2010/04/rails-to_json-or-as_json/
精彩评论