How to build a JSON response made up of multiple models in Rails
我有
1 2 3 4 5 6 7 8 9 | { "user": {"username":"Bob!","foo":"whatever","bar":"hello!"}, "items": [ {"id":1,"name":"one","zim":"planet","gir":"earth"}, {"id":2,"name":"two","zim":"planet","gir":"mars"} ] } |
但是,我的
更新
下一部分包含原始问题。最后一部分显示了新的解决方案。
我的骇客
home_controller.rb
1 2 3 4 5 6 7 8 9 | class HomeController < ApplicationController def observe respond_to do |format| format.js { render :json => Observation.new(current_user, @items).to_json } end end end |
观察文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # 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 |
妈你看没有更多的骇客!
改写
ActiveRecord :: Serialization#as_json文档非常稀疏。这是摘要:
1 2 | as_json(options = nil) [show source] |
有关
该代码没有技巧
user.rb
1 2 3 4 5 6 7 8 | class User < ActiveRecord::Base def as_json(options) options = { :only => [:username], :methods => [:foo, :bar] }.merge(options) super(options) end end |
item.rb
1 2 3 4 5 6 7 8 | class Item < ActiveRecord::Base def as_json(options) options = { :only => [:id, name], :methods => [:zim, :gir] }.merge(options) super(options) end end |
home_controller.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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 |
已编辑为使用
您可以在控制器中呈现所需的JSON,而无需帮助程序模型。
1 2 3 4 5 6 7 8 9 10 | 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 |
确保将
万一有人在寻找替代解决方案,这就是我在Rails 4.2中解决此问题的方式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | def observe @item = some_item @user = some_user respond_to do |format| format.js do serialized_item = ItemSerializer.new(@item).attributes serialized_user = UserSerializer.new(@user).attributes render :json => { :item => serialized_item, :user => serialized_user } end end end |
这将两个对象的序列化版本作为JSON返回,可通过
现在有很多新的Gems用于构建JSON,对于这种情况,我发现最合适的是Jsonify:
https://github.com/bsiggelkow/jsonify
https://github.com/bsiggelkow/jsonify-rails
这允许您从模型中建立属性和数组的混合。
有效答案#2为避免json被"转义",请手动建立数据结构,然后对其调用一次to_json。它可能会有些罗word,但是您可以在控制器中完成所有操作,或者将其作为
1 2 3 4 5 6 7 8 9 10 | 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 |