rails fast custom ruby-on-rails-3.2 active-model-serializers

ruby-on-rails-3.2 - custom - ruby on rails fast json



Use active_model_serializer con un objeto que no sea ActiveRecord (6)

Tengo un objeto modelo que no desciende de ActiveRecord :: Base y no está almacenado en la base de datos. Creé un serializador para él (con el mismo nombre + "Serializador"), y en mi controlador estoy llamando a render json: object_instance .

El resultado es una excepción desde lo profundo del render .

Implementé un método as_json que as_json una instancia del serializador y lo llama, pero el resultado es un método faltante en el objeto, read_attribute_for_serialization .

Quiero que mi objeto actúe como un objeto compatible con ActiveModel al menos en lo que respecta al Active Model Serializer, pero no veo ninguna referencia a esto en su documentación.


Ampliando la respuesta de @ ratbeard, los siguientes trabajos funcionan con cualquier versión de Active_model_serializer 0.9.xy superior. Incluí la cantidad mínima de clases active_support y active_model necesarias para que el objeto hash serializable PORO funcione con los serializadores activemodel fuera de los rieles. A mis fines como una optimización, paso una matriz de objetos serializada previamente calculada en otra parte de la aplicación. En lugar de volver a calcular, puede sobrecargar el inicializador en la subclase ActiveModel :: Serializer para pasarlo si está disponible.

lib / serializable_hash.rb

class SerializableHash < Hash alias :read_attribute_for_serialization :[] end

aplicación / serializadores / correo electrónico / 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

Para completar, también incluyo esta versión alternativa que usa una variable de instancia en lugar del hash serializable:

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

Luego, para usar serializar el objeto de nivel superior simplemente haría

require ''app/serializers/email/foo_serializer'' require ''app/serializers/email/bar_serializer'' Email::FooSerializer.new(Foo.first).as_json

O si desea utilizar la matriz serializada precomputada de barras:

# 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


El objeto modelo necesita incluirlo así:

class ModelName include ActiveModel::SerializerSupport end

Esto implementa los métodos necesarios dentro del objeto y también descubre automáticamente que el serializador coincide con el nombre del objeto, por lo que se puede usar de forma transparente como un objeto ActiveRecord.

Esto funciona con active_model_serializers versión 0.8.1 hasta al menos 0.9.3.


Me encontré con esto ayer mientras actualizaba a Rails 4.2. ActiveModel::SerializerSupport se ha eliminado para 0.10-stable. Terminé simplemente agregando un alias a mi PORO que parecía hacer el truco:

alias :read_attribute_for_serialization :send

(active_model_serializers 0.10.0.rc2)

También deberá agregar include ActiveModel::Model en su clase.


Mi cuenta es demasiado nueva para comentar sobre la respuesta de Karl Wilbur, pero aquí está el código que agregué para que pudiera pasar un objeto hash para serializar:

class SerializableHash < Hash alias :read_attribute_for_serialization :[] end

Uso:

o = SerializableHash.new(user: current_user, account: current_account) respond_with(o, serializer: SettingsSerializer)


Siguiendo con la respuesta de mutexkid, con active_model_serializers 0.10.0.rc4, se requiere lo siguiente para hacer que un objeto Ruby antiguo se vea bien con un serializador:

PORO:

class SearchResult include ActiveModel::Serialization attr_reader :stories, :users, :friends def initialize(search:) @stories = search.stories @users = search.users @friends = search.friends end end

Serializador:

class SearchResultSerializer < ActiveModel::Serializer attributes :stories, :users, :friends end


a partir de active_model_serializers 0.10.x y Rails 4.2, esto es lo que se requiere para usar un objeto Ruby antiguo y plano con serializadores modelo activos:

Objeto simple de rubí antiguo:

class SearchResult extend ActiveModel::Naming include ActiveModel::Serialization attr_accessor :stories, :users, :friends def id hash end def initialize(search:) @stories = search.stories @users = search.users @friends = search.friends end def attributes { stories: stories, users: users, friends: friends } end end

Serializador:

class SearchResultSerializer < ActiveModel::Serializer attributes :stories, :users, :friends end