Rails中to_json的默认值为:include
让我们说我有一个属于用户的模型Post。 要转换为json,我会做这样的事情
@reply.to_json(:include => {:user => {:only => [:email, :id]}, :only => [:title, :id])
但是,我想为此设置一些默认值,所以我不必每次都指定: 我试图覆盖as_json来实现这一目标。 当我在User模型中添加as_json时,在我执行@ user.to_json时调用它,但是当用户包含在@ reply.to_json中时,忽略了用户的重写as_json。
我该如何工作?
谢谢
您可以通过覆盖模型中的serializable_hash
来实现此目的,如下所示:
class Reply < ActiveRecord::Base def serializable_hash(options={}) options = { :include => {:user => {:only => [:email, :id]}, :only => [:title, :id] }.update(options) super(options) end end
这将影响所有可序列化的方法,包括serializable_hash
, to_json
和to_xml
。
在回复模型中:
def as_json(options = {}) super options.merge(:methods => [:user], :only => [:id, :title]) end
在用户模型中:
def as_json(options = {}) super options.merge(:only => [:id, :email]) end
当关联作为方法而不是include包含时,它将在其上运行.to_json。
您可以向ActiveRecord :: Base添加另一个方法,例如self.to_minimal_json(* only_fields)并在那里构建您的.to_json调用。
不引人注目,但可能会奏效。
所以我发现问题是对于包含,而不是调用as_json来生成json,Rails直接调用serializable_hash。 猴子修补修复了这个问题。 把它放在初始化器中
module ActiveRecord #:nodoc: module Serialization def serializable_hash(options = nil) options = options.try(:clone) || {} options[:except] = Array.wrap(options[:except]).map { |n| n.to_s } options[:except] |= Array.wrap(self.class.inheritance_column) hash = super(options) #serializable_add_includes(options) do |association, records, opts| #hash[association] = records.is_a?(Enumerable) ? #records.map { |r| r.serializable_hash(opts) } : #records.serializable_hash(opts) #end serializable_add_includes(options) do |association, records, opts| hash[association] = records.is_a?(Enumerable) ? records.map { |r| r.as_json(opts.merge(:no_root => true)) } : records.as_json(opts.merge(:no_root => true)) end hash end end end module ActiveModel # == Active Model JSON Serializer module Serializers module JSON def as_json(options = nil) hash = serializable_hash(options) if include_root_in_json and !options[:no_root] custom_root = options && options[:root] hash = { custom_root || self.class.model_name.element => hash } end hash end end end end
注意serializable_hash调用是如何用as_json替换的(带有一个额外的参数来阻止在include中添加root)。 现在,如果你的模型中有as_json,即使是include,也会调用它
由于选项在某些情况下可能为零,我们最好注意一下:
module ActiveModel # == Active Model JSON Serializer module Serializers module JSON def as_json(options) options ||= {} hash = serializable_hash(options) if include_root_in_json and !options[:no_root] custom_root = options && options[:root] hash = { custom_root || self.class.model_name.element => hash } end hash end end end end