По умолчанию для to_json в Rails с: include
Скажем, у меня есть модель Post, которая принадлежит пользователю. Чтобы преобразовать в json, я делаю что-то вроде этого
@reply.to_json(:include => {:user => {:only => [:email, :id]},
:only => [:title, :id])
Однако, я хочу установить некоторые значения по умолчанию для этого, поэтому мне не нужно указывать: только каждый раз. Я пытаюсь переопределить as_json, чтобы выполнить это. Когда я добавляю as_json в модель User, он вызывается, когда я делаю @user.to_json, но когда пользователь включен в @reply.to_json, мой overriden as_json для пользователя игнорируется.
Как мне сделать эту работу?
Спасибо
Ответы
Ответ 1
Вы можете сделать это, переопределив 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
.
Ответ 2
В модели Reply:
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.
Ответ 3
Вы можете добавить еще один метод в ActiveRecord:: Base, например self.to_minimal_json (* only_fields) и создать свой вызов .to_json.
неважно, но может работать.
Ответ 4
Итак, я выяснил, что проблема заключается в том, что для включения вместо вызова 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 (с дополнительным параметром для добавления добавления root в include). Теперь, если у вас есть as_json в вашей модели, он будет вызываться даже в случае включения
Ответ 5
Поскольку параметры могут при обстоятельствах быть нуль, нам лучше знать об этом:
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