I have User
and Item
models. I'd like to build a JSON response that looks like this:
{
"user":
{"username":"Bob!","foo":"whatever","bar":"hello!"},
"items": [
{"id":1, "name":"one", "zim":"planet", "gir":"earth"},
{"id":2, "name":"two", "zim":"planet", "gir":"mars"}
]
}
However, my User
and Item
model have more attributes than just those. I found a way to get this to work, but beware, it's not pretty... Please help...
The next section contains the original question. The last section shows the new solution.
class HomeController < ApplicationController
def observe
respond_to do |format|
format.js { render :json => Observation.new(current_user, @items).to_json }
end
end
end
# NOTE: this is not a subclass of ActiveRecord::Base
# this class just serves as a container to aggregate all "observable" objects
class Observation
attr_accessor :user, :items
def initialize(user, items)
self.user = user
self.items = items
end
# The JSON needs to be decoded before it's sent to the `to_json` method in the home_controller otherwise the JSON will be escaped...
# What a mess!
def to_json
{
:user => ActiveSupport::JSON.decode(user.to_json(:only => :username, :methods => [:foo, :bar])),
:items => ActiveSupport::JSON.decode(auctions.to_json(:only => [:id, :name], :methods => [:zim, :gir]))
}
end
end
as_json
insteadThe ActiveRecord::Serialization#as_json docs are pretty sparse. Here's the brief:
as_json(options = nil)
[show source]
For more information on to_json
vs as_json
, see the accepted answer for Overriding to_json in Rails 2.3.5
class User < ActiveRecord::Base
def as_json(options)
options = { :only => [:username], :methods => [:foo, :bar] }.merge(options)
super(options)
end
end
class Item < ActiveRecord::Base
def as_json(options)
options = { :only => [:id, name], :methods => [:zim, :gir] }.merge(options)
super(options)
end
end
class HomeController < ApplicationController
def observe
@items = Items.find(...)
respond_to do |format|
format.js do
render :json => {
:user => current_user || {},
:items => @items
}
end
end
end
end
EDITED to use as_json
instead of to_json
. See How to override to_json in Rails? for a detailed explanation. I think this is the best answer.
You can render the JSON you want in the controller without the need for the helper model.
def observe
respond_to do |format|
format.js do
render :json => {
:user => current_user.as_json(:only => [:username], :methods => [:foo, :bar]),
:items => @items.collect{ |i| i.as_json(:only => [:id, :name], :methods => [:zim, :gir]) }
}
end
end
end
Make sure ActiveRecord::Base.include_root_in_json
is set to false or else you'll get a 'user' attribute inside of 'user'. Unfortunately, it looks like Arrays do not pass options
down to each element, so the collect
is necessary.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With