How do you initialize an ActiveModel::Serializer class with an ActiveRecord::Relation array?

五迷三道 提交于 2019-11-28 15:43:26
SandOnTeeth

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
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!