36

我有一个模型对象,它不是 ActiveRecord::Base 的后代,也没有存储在数据库中。我为它创建了一个序列化程序(具有相同的名称+“序列化程序”),并在我的控制器中调用render json: object_instance.

结果是来自内部深处的异常render

我实现了一个as_json实例化序列化程序并调用它的方法,但结果是对象中缺少一个方法,read_attribute_for_serialization.

至少就 Active Model Serializer 而言,我希望我的对象能够像 ActiveModel 兼容的对象一样工作,但我在他们的文档中没有看到对此的任何引用。

4

6 回答 6

59

因此模型对象需要包含它:

# active_model_serializers 0.10+
class ModelName
  include ActiveModel::Serialization
end

# active_model_serializers < 0.10
class ModelName
  include ActiveModel::SerializerSupport
end

这实现了对象中所需的方法,并自动发现与对象名称匹配的序列化程序,因此可以像 ActiveRecord 对象一样透明地使用它。

这适用于 active_model_serializers 版本 0.8.1 到至少 0.9.3。

于 2014-02-11T19:10:37.067 回答
13

在 mutexkid 回答之后,使用 active_model_serializers 0.10.0.rc4,需要以下内容才能使普通的旧 ruby​​ 对象与序列化程序一起使用:

宝罗:

class SearchResult
  include ActiveModel::Serialization

  attr_reader :stories, :users, :friends

  def initialize(search:)
    @stories = search.stories
    @users = search.users
    @friends = search.friends
  end
end

序列化器:

class SearchResultSerializer < ActiveModel::Serializer
  attributes :stories, :users, :friends
end
于 2016-03-11T11:06:35.710 回答
7

我昨天在升级到 Rails 4.2 时遇到了这个问题。ActiveModel::SerializerSupport已为 0.10-stable 移除。我最终只是为我的 PORO 添加了一个别名,这似乎可以解决问题:

  alias :read_attribute_for_serialization :send

(active_model_serializers 0.10.0.rc2)

您还需要ActiveModel::Model在您的课程中添加包含。

于 2015-08-11T07:56:14.183 回答
6

从 active_model_serializers 0.10.x 和 Rails 4.2 开始,以下是使用带有活动模型序列化器的普通旧 ruby​​ 对象的要求:

普通的旧红宝石对象:

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

序列化器:

class SearchResultSerializer < ActiveModel::Serializer
  attributes :stories, :users, :friends
end
于 2016-01-13T19:39:18.077 回答
5

我的帐户太新,无法评论 Karl Wilbur 的回答,但这是我添加的代码,因此我可以传入一个哈希对象进行序列化:

class SerializableHash < Hash
  alias :read_attribute_for_serialization :[]
end

用法:

  o = SerializableHash.new(user: current_user, account: current_account)
  respond_with(o, serializer: SettingsSerializer)
于 2015-09-03T14:44:07.380 回答
0

扩展@ratbeard 的答案,以下适用于任何 active_model_serializer 0.9.x 及更高版本。我包含了使 PORO 可序列化散列对象与 rails 之外的 activemodel 序列化程序一起工作所需的最少量的 active_support 和 active_model 类。出于我的优化目的,我传入了一个预先计算的序列化对象数组,该数组在应用程序的其他地方计算。您可以重载 ActiveModel::Serializer 子类中的初始化程序,而不是重新计算,以便在可用时将其传递。

lib/serializable_hash.rb

class SerializableHash < Hash
  alias :read_attribute_for_serialization :[]
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)
    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
于 2015-12-03T02:11:58.507 回答