How to initialize an ActiveModel :: Serializer class using an ActiveRecord :: Relation array?

I have a serializer

class FundingSerializer < ActiveModel::Serializer attributes :id, has_one :user has_one :tournament embed :ids, include: true end 

This is initialized by the corresponding associations.

 FundingSerializer.new(Funding.first).to_json 

gives

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

but

 FundingSerializer.new(Funding.all).to_json 

gets this error.

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

I don't want to just display json: Funding.all because I would like to pass this json to other objects in my rails application and using the angularjs application. Thank,

+45
ruby-on-rails-4 active-model-serializers
Jul 09 '13 at 7:49
source share
8 answers

Now you can do it this way (using AMS v0.10.2):

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

EDIT (03.03.2017)
This method no longer works. Use the answer of aNoble :

 ActiveModelSerializers::SerializableResource.new(Funding.all).to_json 
+5
Sep 04 '16 at 15:39
source share

I think this is what you are looking for:

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

See this Thoughtbot blog post for an example.

+170
Jul 29 '13 at 1:46
source share

I'm not sure if this is an idiomatic solution, but it should work:

 Funding.all.map{|f| FundingSerializer.new(f)}.to_json 
+26
Jul 10 '13 at 14:14
source share

You can also explicitly provide a collection serializer.

 render json: Funding.all, serializer: ActiveModel::ArraySerializer, each_serializer: FundingSerializer 
+6
Sep 24 '15 at 18:53
source share

It looks like they are correcting this again in the latest version of ActiveModel :: Serializers emulation. You can no longer call to_json on an ArraySerializer (which is not ActiveModel :: Serializer :: ArraySerializer).

Here is what I did to get around this.

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

Calling a topic will give you the json you follow.

Here are some more resources that are immersed in the test setup for further reading: http://eclips3.net/2015/01/24/testing-active-model-serializer-with-rspec/ https://robots.thoughtbot.com/ validating-json-schemas-with-an-rspec-matcher

+5
Jun 17 '15 at 16:44
source share

Testing the response for active_model_serializers with version >= 0.10.0 I made this simple helper for 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 

So you can just test:

 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 

I hope this can be helpful to someone.

+3
Jul 13 '15 at 13:20
source share

This worked for me in version 0.10.2 :

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

+2
Sep 21 '16 at 2:21
source share

Assuming you have a serializer class (Foo) that doesn't match your resource name (Bar), I use the following approach to simply serialize objects:

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

Let the Foo serializer inherit BaseSerializer:

 class FooSerializer < BaseSerializer ... end 

use FooSerializer in the controller or externally:

 bar = Bar.all FooSerializer.collection_serialize(bar).to_json 
0
Oct 12 '16 at 5:11
source share



All Articles