开发者

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/

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜