В дополнение к ответу @ratbeard следующее работает с любой версией active_model_serializer 0.9.x и выше. Я включил минимальное количество классов active_support и active_model, необходимых для того, чтобы сериализуемый хеш-объект PORO работал с сериализаторами ActiveModel вне рельсов. В моих целях в качестве оптимизации я передаю предварительно вычисленный сериализованный массив объектов, который вычисляется в другом месте приложения. Вместо повторного вычисления вы можете перегрузить инициализатор в подклассе ActiveModel::Serializer, чтобы передать его, если он доступен.
lib/serializable_hash.rb
class SerializableHash < Hash
alias :read_attribute_for_serialization :[]
end
app/serializers/email/foo_serializer.rb
require 'active_model/serializer'
require 'active_support/core_ext/object'
require 'active_support/inflector'
require 'active_support/notifications'
class Email::FooSerializer < ActiveModel::Serializer
attributes :id, :bars, :created_at, :updated_at
def initialize(foo, precomputed_serialized_array_of_bars =nil)
unless serialized_bars
serialized_bars = {}
foo.bar.each do | bar |
serialized_searches[bar.baz] ||= []
serialized_searches[bar.baz] << Email::BarSerializer.new(bar).attributes
end
end
super(SerializableHash[
id: foo.id,
bars: serialized_bars,
created_at: foo.created_at
updated_at: foo.updated_at
])
end
end
Для полноты я также включил эту альтернативную версию, в которой вместо сериализуемого хэша используется переменная экземпляра:
app/serializers/email/foo_serializer.rb
require 'active_model/serializer'
require 'active_support/core_ext/object'
require 'active_support/inflector'
require 'active_support/notifications'
class Email::FooSerializer < ActiveModel::Serializer
attributes :id, :bars, :created_at, :updated_at
def initialize(foo, precomputed_serialized_array_of_bars=nil)
@bars = precomputed_serialized_array_of_bars
super(foo)
end
def bars
if @bars
return @bars
else
serialized_bars = {}
object.bars.each do | bar |
serialized_bars[bar.baz] ||= []
serialized_bars[bar.baz] << Email::BarSerializer.new(bar).attributes
end
return serialized_bars
end
end
end
Затем, чтобы использовать сериализацию объекта верхнего уровня, вы бы просто сделали
require 'app/serializers/email/foo_serializer'
require 'app/serializers/email/bar_serializer'
Email::FooSerializer.new(Foo.first).as_json
ИЛИ, если вы хотите использовать предварительно вычисленный сериализованный массив баров:
# pre-compute array_of_serialized_bars somewhere up here
require 'app/serializers/email/foo_serializer'
require 'app/serializers/email/bar_serializer'
Email::FooSerializer.new(Foo.first, array_of_pre_serialized_bars).as_json
person
Jesse Sanford
schedule
03.12.2015