Я имею User
и Item
модели. Я хотел бы создать ответ JSON, который похож на это:
{
"user":
{"username":"Bob!","foo":"whatever","bar":"hello!"},
"items": [
{"id":1, "name":"one", "zim":"planet", "gir":"earth"},
{"id":2, "name":"two", "zim":"planet", "gir":"mars"}
]
}
Однако мой User
и Item
модель имеет больше атрибутов, чем просто они. Я нашел способ заставить это работать, но остерегаться, это не симпатично... Помогите...
Следующий раздел содержит исходный вопрос. Последний раздел показывает новое решение.
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
вместо этогоActiveRecord:: документы Serialization#as_json довольно редки. Вот резюме:
as_json(options = nil)
[show source]
Для получения дополнительной информации о to_json
по сравнению с as_json
, см. принятый ответ для Переопределения to_json в направляющих 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
ИЗМЕНИТЬ , чтобы использовать as_json
вместо to_json
. См. Как переопределить to_json в Rails? для подробного объяснения. Думаю, это лучший ответ.
Вы можете визуализировать нужный JSON в контроллере без необходимости использования вспомогательной модели.
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
Убедитесь, что для ActiveRecord :: Base.include_root_in_json
установлено значение false, иначе вы получите атрибут «пользователь» внутри «пользователя». К сожалению, похоже, что массивы не передают options
каждому элементу, поэтому требуется collect
.
Рабочий ответ №2 Чтобы избежать проблемы с "экранированием" вашего json, создайте структуру данных вручную, а затем вызовите для нее to_json один раз . Это может быть немного многословным, но вы можете сделать все это в контроллере или абстрагировать его для отдельных моделей как to_hash
или что-то в этом роде.
def observe
respond_to do |format|
format.js do
render :json => {
:user => {:username => current_user.username, :foo => current_user.foo, :bar => current_user.bar},
:items => @items.collect{ |i| {:id => i.id, :name => i.name, :zim => i.zim, :gir => i.gir} }
}
end
end
end