如何使用ActiveRecord :: Relation数组初始化ActiveModel :: Serializer类?

时间:2013-07-09 07:49:50

标签: ruby-on-rails-4 active-model-serializers

我有一个序列化器

class FundingSerializer < ActiveModel::Serializer
  attributes :id, 

  has_one :user
  has_one :tournament
  embed :ids, include: true
end

用适当的关联初始化

FundingSerializer.new(Funding.first).to_json

产量

"{\"users\":[{\"id\":2,\"first_name\":\"Nick\"}],\"tournaments\":[{\"id\":1,\"end_date\":\"2013-07-21T23:18:54.981Z\",\"start_date\":\"2013-07-14T23:18:54.980Z\"}],\"funding\":{\"id\":1}}"

但是,

FundingSerializer.new(Funding.all).to_json

出现此错误。

undefined method `read_attribute_for_serialization' for #<ActiveRecord::Relation::ActiveRecord_Relation_Funding:0x007f998910a250>
    from /Users/nicholasshook/.rvm/gems/ruby-2.0.0-p247@pokerfund/gems/activerecord-4.0.0/lib/active_record/relation/delegation.rb:121:in `method_missing'
    from /Users/nicholasshook/.rvm/gems/ruby-2.0.0-p247@pokerfund/gems/activerecord-4.0.0/lib/active_record/relation/delegation.rb:68:in `method_missing'
    from /Users/nicholasshook/.rvm/gems/ruby-2.0.0-p247@pokerfund/gems/active_model_serializers-0.8.1/lib/active_model/serializer.rb:99:in `block in attribute'
    from (eval):3:in `_fast_attributes'
    from /Users/nicholasshook/.rvm/gems/ruby-2.0.0-p247@pokerfund/gems/active_model_serializers-0.8.1/lib/active_model/serializer.rb:466:in `rescue in attributes'
    from /Users/nicholasshook/.rvm/gems/ruby-2.0.0-p247@pokerfund/gems/active_model_serializers-0.8.1/lib/active_model/serializer.rb:454:in `attributes'
    from /Users/nicholasshook/.rvm/gems/ruby-2.0.0-p247@pokerfund/gems/active_model_serializers-0.8.1/lib/active_model/serializer.rb:478:in `_serializable_hash'
    from /Users/nicholasshook/.rvm/gems/ruby-2.0.0-p247@pokerfund/gems/active_model_serializers-0.8.1/lib/active_model/serializer.rb:360:in `serializable_hash'
    from /Users/nicholasshook/.rvm/gems/ruby-2.0.0-p247@pokerfund/gems/active_model_serializers-0.8.1/lib/active_model/serializer.rb:344:in `as_json'
    from /Users/nicholasshook/.rvm/gems/ruby-2.0.0-p247@pokerfund/gems/activesupport-4.0.0/lib/active_support/json/encoding.rb:50:in `block in encode'
    from /Users/nicholasshook/.rvm/gems/ruby-2.0.0-p247@pokerfund/gems/activesupport-4.0.0/lib/active_support/json/encoding.rb:81:in `check_for_circular_references'
    from /Users/nicholasshook/.rvm/gems/ruby-2.0.0-p247@pokerfund/gems/activesupport-4.0.0/lib/active_support/json/encoding.rb:49:in `encode'
    from /Users/nicholasshook/.rvm/gems/ruby-2.0.0-p247@pokerfund/gems/activesupport-4.0.0/lib/active_support/json/encoding.rb:34:in `encode'
    from /Users/nicholasshook/.rvm/gems/ruby-2.0.0-p247@pokerfund/gems/activesupport-4.0.0/lib/active_support/core_ext/object/to_json.rb:16:in `to_json'
    from /Users/nicholasshook/.rvm/gems/ruby-2.0.0-p247@pokerfund/gems/active_model_serializers-0.8.1/lib/active_model/serializer.rb:333:in `to_json'
    from (irb):1
    from /Users/nicholasshook/.rvm/gems/ruby-2.0.0-p247@pokerfund/gems/railties-4.0.0/lib/rails/commands/console.rb:90:in `start'
    from /Users/nicholasshook/.rvm/gems/ruby-2.0.0-p247@pokerfund/gems/railties-4.0.0/lib/rails/commands/console.rb:9:in `start'
    from /Users/nicholasshook/.rvm/gems/ruby-2.0.0-p247@pokerfund/gems/railties-4.0.0/lib/rails/commands.rb:64:in `<top (required)>'

我不想简单地渲染json:Funding.all因为我想将这个json传递给我的rails应用程序中的其他对象并使用angularjs应用程序。谢谢,

8 个答案:

答案 0 :(得分:174)

我认为这就是你要找的东西:

ActiveModel::ArraySerializer.new(Funding.all, each_serializer: FundingSerializer).to_json

有关示例,请参阅此Thoughtbot blog post

答案 1 :(得分:28)

我不确定这是否是惯用的解决方案,但它应该有效:

Funding.all.map{|f| FundingSerializer.new(f)}.to_json

答案 2 :(得分:8)

现在你可以这样做(使用AMS v0.10.2):

z ~ x + y + x:id
编辑(03.03.2017)
此方法不再有效。使用aNoble's回答:

ActiveModel::Serializer.serializer_for(Funding.all).to_json

答案 3 :(得分:8)

这适用于版本0.10.2

ActiveModelSerializers::SerializableResource.new(Funding.all, each_serializer: FundingSerializer).to_json

答案 4 :(得分:6)

您也可以明确提供集合序列化程序。

render json: Funding.all, serializer: ActiveModel::ArraySerializer, each_serializer: FundingSerializer

答案 5 :(得分:5)

看起来他们正在最新的ActiveModel :: Serializers gem版本中再次调整它。你不能再在ArraySerializer上调用to_json(它不是ActiveModel :: Serializer :: ArraySerializer)。

这就是我做的事情。

let(:resource)        { Funding.all }
let(:serializer)      { ActiveModel::Serializer::ArraySerializer.new(resource, each_serializer: FundingSerializer)
let(:serialization)   { ActiveModel::Serializer::Adapter.create(serializer) }
subject               { JSON.parse(serialization.to_json) }

调用主题将为您提供您所追求的json。

以下是一些资源,这些资源可用于进一步阅读测试设置: http://eclips3.net/2015/01/24/testing-active-model-serializer-with-rspec/ https://robots.thoughtbot.com/validating-json-schemas-with-an-rspec-matcher

答案 6 :(得分:3)

使用版本active_model_serializers测试>= 0.10.0的响应我为RSpec完成了这个简单的帮助:

module AMSHelper
  def ams_array_serializer(collection, options: {}, adapter: :json)
    serializer = ActiveModel::Serializer::ArraySerializer.new(collection)
    adapter_class = ActiveModel::Serializer::Adapter.adapter_class(adapter)
    adapter_class.new(serializer, options)
  end

  def ams_serializer(object, options: {}, adapter: :json)
    serializer = ActiveModel::Serializer.serializer_for(object).new(object)
    adapter_class = ActiveModel::Serializer::Adapter.adapter_class(adapter)

    adapter_class.new(serializer, options)
  end
end

RSpec.configure do |config|
  config.include AMSHelper, type: :request
end

所以你可以简单地测试:

RSpec.describe "Posts", type: :request do
  describe "GET /" do
    it "returns http success" do
      get posts_path
      expect(response_body).to eq(ams_array_serializer(Post.all).to_json)
    end
  end
end

我希望这对某人有用。

答案 7 :(得分:0)

假设您的序列化程序类(Foo)与您的资源名称(Bar)不匹配,我使用以下方法轻松序列化对象:

class BaseSerializer < ActiveModel::Serializer
  def self.collection_serialize(resources)
    ActiveModelSerializers::SerializableResource.new(resources, each_serializer: self)
  end
end

让Foo序列化程序继承BaseSerializer:

class FooSerializer < BaseSerializer
  ...
end

在控制器或外部使用FooSerializer:

bar = Bar.all
FooSerializer.collection_serialize(bar).to_json