I have a serializer
class FundingSerializer < ActiveModel::Serializer
attributes :id,
has_one :user
has_one :tournament
embed :ids, include: true
end
That initializes with the proper associations
FundingSerializer.new(Funding.first).to_json
yields
"{\"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 do not want to simply render json: Funding.all because I would like to pass this json around to other objects in my rails application and with an angularjs app. Thanks,
Now you can do that in this way (using AMS v0.10.2):
ActiveModel::Serializer.serializer_for(Funding.all).to_json
EDIT (03.03.2017)
This method is not working anymore. Use aNoble's answer:
ActiveModelSerializers::SerializableResource.new(Funding.all).to_json
I think this is what you're looking for:
ActiveModel::ArraySerializer.new(Funding.all, each_serializer: FundingSerializer).to_json
See this Thoughtbot blog post for an example.
I'm not sure if this is an idiomatic solution, but it should work:
Funding.all.map{|f| FundingSerializer.new(f)}.to_json
This worked for me in version 0.10.2
:
ActiveModelSerializers::SerializableResource.new(Funding.all, each_serializer: FundingSerializer).to_json
You can explicitly provide the collection serializer as well.
render json: Funding.all, serializer: ActiveModel::ArraySerializer, each_serializer: FundingSerializer
Looks like they are adjusting this again in the newest ActiveModel::Serializers gem version. You no longer can call to_json on the ArraySerializer (which is not ActiveModel::Serializer::ArraySerializer).
Here's what I did to get around it.
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 subject will get you the json you are after.
Here are a couple of more resources which dive into testing 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
Testing the response for active_model_serializers
with version >= 0.10.0
I've done 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 simply test with:
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 could be useful for someone.
assume you have a serializer class(Foo) not match your resources name(Bar), I use following approach to easily serialize objects:
class BaseSerializer < ActiveModel::Serializer
def self.collection_serialize(resources)
ActiveModelSerializers::SerializableResource.new(resources, each_serializer: self)
end
end
let Foo serializer inherit BaseSerializer:
class FooSerializer < BaseSerializer
...
end
use FooSerializer in controller or outside:
bar = Bar.all
FooSerializer.collection_serialize(bar).to_json
来源:https://stackoverflow.com/questions/17542793/how-do-you-initialize-an-activemodelserializer-class-with-an-activerecordrel