【问题标题】:How do you initialize an ActiveModel::Serializer class with an ActiveRecord::Relation array?如何使用 ActiveRecord::Relation 数组初始化 ActiveModel::Serializer 类?
【发布时间】:2013-07-06 17:44:12
【问题描述】:

我有一个序列化器

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 应用程序中的其他对象。谢谢,

【问题讨论】:

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


【解决方案1】:

我想这就是你要找的东西:

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

请参阅此Thoughtbot blog post 以获取示例。

【讨论】:

  • 太棒了,正是我需要的。这应该在 github 上的 AMS wiki 上。
  • 这给了我uninitialized constant ActiveModel::ArraySerializer
  • 这不适用于“active_model_serializers”gem >= 0.10.0。 ::ActiveModel::ArraySerializer 被移动到 ::ActiveModel::Serializer::ArraySerializer 并且类的结构发生了显着变化。
  • @ZekeFast 对于任何在这里搜索最新 AMS 大师(截至 2016 年 4 月)并发现自己正在处理此问题的人,请记住您需要使用 ActiveModel: :Serializer::CollectionSerializer 因为显然 AMS 团队将很快弃用其他类。 ActiveModel::Serializer::CollectionSerializer.new(object.myrelation, each_serializer: MySerializer)
  • ActiveModel::Serializer::CollectionSerializer.new(object.myrelation, serializer: MySerializer) 为我工作(each_serializer 选项被忽略)
【解决方案2】:

我不确定这是否是惯用的解决方案,但它应该可以工作:

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

【讨论】:

  • 确实有效,我只是认为会有一个类似于 ActiveModel::ArraySerializer.new 的解决方案......
  • ActiveModel::ArraySerializer 的底层基本上就是这个精确的实现。映射集合并返回一个序列化实例。
  • 在“active_model_serializers”>= 0.10.0 上无法正常工作。
【解决方案3】:

这在 0.10.2 版本中对我有用:

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

【讨论】:

  • ActiveModelSerializers::SerializableResource 是当前的官方 API,这个答案是正确的,从版本 0.10.2 开始。
  • 确认这是目前唯一的正确答案。
【解决方案4】:

现在您可以通过这种方式执行此操作(使用 AMS v0.10.2):

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

编辑 (03.03.2017)
这种方法不再起作用了。使用aNoble's 回答:

ActiveModelSerializers::SerializableResource.new(Funding.all).to_json

【讨论】:

  • 自版本0.10.2 aNoble 提供正确答案。另外,请查看有关该主题的 the documentation
  • 我使用的是 AMS 0.10.2,ActiveModel::Serializer.serializer_for(Leaderboard.all).to_json,即使有几十条排行榜记录,也总是返回“{}”
  • @MuhammadFaisalIqbal 请检查我的更新答案
【解决方案5】:

看起来他们在最新的 ActiveModel::Serializers gem 版本中再次对此进行了调整。您不再可以在 ArraySerializer(不是 ActiveModel::Serializer::ArraySerializer)上调用 to_json。

这是我为解决这个问题所做的。

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】:

    您也可以显式提供集合序列化程序。

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

    【讨论】:

    • 这是正确的答案,至少对于
    • 当我删除序列化程序时它对我有用:ActiveModel::ArraySerializer
    【解决方案7】:

    使用版本&gt;= 0.10.0 测试active_model_serializers 的响应我已经为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
    

    我希望这对某人有用。

    【讨论】:

    【解决方案8】:

    假设您有一个序列化程序类(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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-10-04
      • 2014-06-02
      • 2022-11-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-08-19
      相关资源
      最近更新 更多