Comment initialisez-vous une classe ActiveModel:: Serializer avec un tableau de relations ActiveRecord::?

J'ai un sérialiseur

class FundingSerializer < ActiveModel::Serializer
  attributes :id, 

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

Qui s'initialise avec les associations appropriées

FundingSerializer.new(Funding.first).to_json

Rendements

"{"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}}"

Mais,

FundingSerializer.new(Funding.all).to_json

Obtient cette erreur.

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)>'

Je ne veux pas simplement rendre json: Funding.tout cela parce que je voudrais passer ce json à d'autres objets dans mon application rails et avec une application angularjs. Merci,

45
demandé sur shicholas 2013-07-09 11:49:50

8 réponses

Maintenant, vous pouvez le faire de cette façon (en utilisant AMS v0. 10. 2):

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

Modifier (03.03.2017)
Cette méthode ne fonctionne plus. Utilisez anoble Réponse:

ActiveModelSerializers::SerializableResource.new(Funding.all).to_json
7
répondu SandOnTeeth 2017-05-23 12:10:11

Je pense que c'est ce que vous cherchez:

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

Voir ce Thoughtbot blog pour un exemple.

173
répondu John 2013-07-30 02:01:50

Je ne suis pas sûr si c'est une solution idiomatique, mais cela devrait fonctionner:

Funding.all.map{|f| FundingSerializer.new(f)}.to_json
27
répondu DNNX 2013-07-10 14:14:58

Vous pouvez également fournir explicitement le sérialiseur de collection.

render json: Funding.all, serializer: ActiveModel::ArraySerializer, each_serializer: FundingSerializer
6
répondu Vignesh Jayavel 2015-09-24 18:53:09

On dirait qu'ils ajustent à nouveau cela dans la nouvelle version de Gem ActiveModel:: Serializers. Vous ne pouvez plus appeler to_json sur le ArraySerializer (qui N'est pas ActiveModel::Serializer:: ArraySerializer).

Voici ce que j'ai fait pour le contourner.

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) }

Appelant le sujet vous obtiendrez le json que vous recherchez.

Voici quelques autres ressources qui plongent dans la configuration de test pour une lecture plus approfondie: http://eclips3.net/2015/01/24/testing-active-model-serializer-with-rspec/ https://robots.thoughtbot.com/validating-json-schemas-with-an-rspec-matcher

5
répondu Mitch Nick 2015-06-17 17:00:56

Tester la réponse pour active_model_serializers avec la version >= 0.10.0 j'ai fait cette aide simple pour 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

Vous pouvez donc simplement tester avec:

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

J'espère que cela pourrait être utile pour quelqu'un.

3
répondu dalpo 2015-07-14 08:54:02

Cela a fonctionné pour moi dans la version 0.10.2:

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

3
répondu aNoble 2016-09-21 02:21:00

Supposons que vous avez une classe de sérialiseur(Foo) ne correspond pas au nom de vos ressources( Bar), j'utilise l'approche suivante pour sérialiser facilement les objets:

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

Laissez Foo serializer hériter BaseSerializer:

class FooSerializer < BaseSerializer
  ...
end

Utilisez FooSerializer dans le contrôleur ou à l'extérieur:

bar = Bar.all
FooSerializer.collection_serialize(bar).to_json
0
répondu Yi Feng Xie 2016-10-12 05:11:20