2014-02-11 2 views
28

У меня есть объект модели, который не спускается с ActiveRecord :: Base и не хранится в базе данных. Я создал для него сериализатор (с тем же именем + «Сериализатор»), и в моем контроллере я звоню render json: object_instance.Использовать active_model_serializer с объектом non-ActiveRecord

Результатом является исключение из глубины render.

Я применил метод as_json, который создает экземпляр сериализатора и вызывает его, но результатом является отсутствующий метод в объекте, read_attribute_for_serialization.

Я хочу, чтобы мой объект действовал как объект, совместимый с ActiveModel, по крайней мере, насколько это касается Active Serializer, но я не вижу ссылки на это в своей документации.

ответ

50

Через несколько часов я наконец нашел решение. Объектная модель должна включать его таким образом:

class ModelName 
    include ActiveModel::SerializerSupport 
end 

Это реализует методы, необходимые в пределах объекта, а также автоматически обнаруживает сериализатору соответствие имя объекта, поэтому его можно использовать прозрачно так же, как объект ActiveRecord.

Работает с active_model_serializers версии 0.8.1 - 0.9.3.

+3

Вы должны принять свой собственный ответ, поскольку он кажется правильным. :) –

+0

Эй, Робин, можете ли вы включить пример своего объекта для людей, которые хотят сделать что-то подобное с нуля? (это неактивный объект записи, включающий поддержку сериализатора) – Will

+0

удалось ли сериализовать массив вложенных сериализованных объектов внутри модели? – Chris

7

Я столкнулся с этим вчера, обновляясь до Rails 4.2. ActiveModel::SerializerSupport удален для 0.10-стабильной. Я в конечном итоге просто добавить псевдоним к моим Порос, который, казалось, сделать трюк:

alias :read_attribute_for_serialization :send 

(active_model_serializers 0.10.0.rc2)

Вы также должны добавить включать ActiveModel::Model в своем классе.

3

Мой счет слишком новый, чтобы прокомментировать ответ Карла Уилбур, но Heres код, который я добавил, чтобы я мог пройти в хэш-объект для сериализации:

class SerializableHash < Hash 
    alias :read_attribute_for_serialization :[] 
end 

Использование:

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

Расширение при ответе @ ratbeard следующее работает с любым active_model_serializer версии 0.9.x и выше. Я включил минимальное количество классов active_support и active_model, необходимых для того, чтобы получить сериализуемый хеш-объект PORO для работы с сериализаторами activemodel вне рельсов. Для моих целей в качестве оптимизации я передаю предварительно вычисленный сериализованный массив объектов, который вычисляется в другом месте приложения. Вместо повторного вычисления вы можете перегрузить инициализатор в подкласс ActiveModel :: Serializer, чтобы передать его, если он доступен.

Библиотека/serializable_hash.rb

class SerializableHash < Hash 
    alias :read_attribute_for_serialization :[] 
end 

приложение/сериализаторов/электронная почта/foo_serializer.гь

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 

Для полноты я также включить этот альтернативный вариант, который использует переменную экземпляр вместо сериализуемой хэш:

приложение/сериализаторы/электронных/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 
+1

'class SerializableHash BF4

3

от active_model_serializers 0.10.x и Rails 4.2, вот то, что требуется, чтобы использовать обычный старый объект рубинового с активными моделью сериализаторами:

Обычный старый объект рубин:

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 

Serializer:

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

с 'active_model_serializers 0.10.0.rc4: я нашел много этой настройки ненужной, см. Мой ответ ниже. Я добавил отдельный ответ, поскольку комментарии не слишком хорошо обрабатывают блоки кода: – b73

10

Исходя из mutexkid ответа, с active_model_serializers 0.10.0.rc4, требуется, чтобы сделать простой старый объект рубин играть хорошо с сериализатором следующее:

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 

Serializer:

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

Это использовало Rails 4.0.13 – b73

+0

Это также документировано (может быть более очевидным) и литировано в 0.10. series: https://github.com/rails-api/active_model_serializers/blob/e1d1a3dbf969cfa48d91e978c8c7fd7e2f098e7c/docs/general/rendering.md#serializing-non-activerecord-objects https://github.com/rails-api/active_model_serializers/blob /e1d1a3dbf969cfa48d91e978c8c7fd7e2f098e7c/docs/ARCHITECTURE.md#what-does-a-serializable-resource-look-like – BF4

+0

Хорошо работает с Rails 5.0.1 и AMS 0.10.4 –

 Смежные вопросы

  • Нет связанных вопросов^_^