Implement support for collection serializers.

This commit is contained in:
Darren Cheng 2016-07-24 15:49:32 -07:00
parent 2a4be72387
commit 6bb205731a
5 changed files with 102 additions and 23 deletions

View file

@ -2,6 +2,10 @@
### 1.5.0 (Next) ### 1.5.0 (Next)
* [#61](https://github.com/ruby-grape/grape-active_model_serializers/pull/61): Adds support for collection serializers - [@drn](https://github.com/drn).
* [#60](https://github.com/ruby-grape/grape-active_model_serializers/pull/60): Namespace serializer inference - [@drn](https://github.com/drn).
* [#59](https://github.com/ruby-grape/grape-active_model_serializers/pull/59): Refactor option and serializer resolution - [@drn](https://github.com/drn).
* [#57](https://github.com/ruby-grape/grape-active_model_serializers/pull/57): Solve line length linter issues - [@drn](https://github.com/drn).
* [#54](https://github.com/ruby-grape/grape-active_model_serializers/pull/54): Adding support for ASM v0.10. Drops support for ASM v0.9 - [@drn](https://github.com/drn). * [#54](https://github.com/ruby-grape/grape-active_model_serializers/pull/54): Adding support for ASM v0.10. Drops support for ASM v0.9 - [@drn](https://github.com/drn).
### 1.4.0 (July 14, 2016) ### 1.4.0 (July 14, 2016)
@ -11,8 +15,8 @@
### v1.3.2 (February 27, 2015) ### v1.3.2 (February 27, 2015)
* [#39](https://github.com/ruby-grape/grape-active_model_serializers/pull/39): Look for namespace and other options to configure serializers - [@jwkoelewijn](https://github.com/jwkoelewijn).
* [#40](https://github.com/ruby-grape/grape-active_model_serializers/pull/40): Use env to pass AMS meta around - [@dblock](https://github.com/dblock). * [#40](https://github.com/ruby-grape/grape-active_model_serializers/pull/40): Use env to pass AMS meta around - [@dblock](https://github.com/dblock).
* [#39](https://github.com/ruby-grape/grape-active_model_serializers/pull/39): Look for namespace and other options to configure serializers - [@jwkoelewijn](https://github.com/jwkoelewijn).
### v1.3.1 (November 20, 2014) ### v1.3.1 (November 20, 2014)

View file

@ -7,9 +7,7 @@ module Grape
end end
def serializer def serializer
@serializer ||= ( serializer_class.new(resource, serializer_options) if serializer_class
serializer_class.new(resource, options) if serializer_class
)
end end
private private
@ -17,13 +15,32 @@ module Grape
attr_accessor :resource, :options attr_accessor :resource, :options
def serializer_class def serializer_class
serializer_class = resource_defined_class return @serializer_class if defined?(@serializer_class)
serializer_class ||= collection_class @serializer_class = resource_defined_class
serializer_class ||= options[:serializer] @serializer_class ||= collection_class
@serializer_class ||= options[:serializer]
@serializer_class ||= namespace_inferred_class
@serializer_class ||= version_inferred_class
@serializer_class ||= resource_serializer_class
end
def serializer_options
if collection_serializer? && !options.key?(:serializer)
options.merge(each_serializer_option)
else
options
end
end
def collection_serializer?
serializer_class == ActiveModel::Serializer.config.collection_serializer
end
def each_serializer_option
serializer_class = options[:each_serializer]
serializer_class ||= namespace_inferred_class serializer_class ||= namespace_inferred_class
serializer_class ||= version_inferred_class serializer_class ||= version_inferred_class
serializer_class ||= resource_serializer_class serializer_class ? { serializer: serializer_class } : {}
serializer_class
end end
def resource_defined_class def resource_defined_class
@ -36,12 +53,13 @@ module Grape
end end
def namespace_inferred_class def namespace_inferred_class
return nil unless options[:for] return nil unless options.key?(:for)
namespace = options[:for].to_s.deconstantize namespace = options[:for].to_s.deconstantize
"#{namespace}::#{resource_serializer_klass}".safe_constantize "#{namespace}::#{resource_serializer_klass}".safe_constantize
end end
def version_inferred_class def version_inferred_class
return nil unless options.key?(:version)
"#{version}::#{resource_serializer_klass}".safe_constantize "#{version}::#{resource_serializer_klass}".safe_constantize
end end
@ -57,14 +75,22 @@ module Grape
end end
def resource_klass def resource_klass
resource.class.name.demodulize resource_class.name.demodulize
end end
def resource_namespace def resource_namespace
klass = resource.class.name.deconstantize klass = resource_class.name.deconstantize
klass.empty? ? nil : klass klass.empty? ? nil : klass
end end
def resource_class
if resource.respond_to?(:to_ary)
resource.try(:klass) || resource.compact.first.class
else
resource.class
end
end
def resource_serializer_class def resource_serializer_class
ActiveModel::Serializer.serializer_for(resource) ActiveModel::Serializer.serializer_for(resource)
end end

View file

@ -1,11 +1,12 @@
require 'pry'
require 'spec_helper' require 'spec_helper'
# asserts serializer resolution order: # asserts serializer resolution order:
# 1. resource_defined_class # V1::UserSerializer # 1. resource_defined_class # V1::UserSerializer
# 2. collection_class # CollectionSerializer # 2. collection_class # CollectionSerializer, V2::UserSerializer
# 3. options[:serializer] # V2::UserSerializer # 3. options[:serializer] # V3::UserSerializer
# 4. namespace_inferred_class # V3::UserSerializer # 4. namespace_inferred_class # V4::UserSerializer
# 5. version_inferred_class # V4::UserSerializer # 5. version_inferred_class # V5::UserSerializer
# 6. resource_serializer_class # UserSerializer # 6. resource_serializer_class # UserSerializer
# 7. missing resource # nil # 7. missing resource # nil
@ -15,15 +16,15 @@ describe Grape::ActiveModelSerializers::SerializerResolver do
let(:options) { let(:options) {
{ {
serializer: options_serializer_class, # options defined serializer: options_serializer_class, # options defined
for: V3::UsersApi, # namespace inference for: V4::UsersApi, # namespace inference
version: 'v4' # version inference version: 'v5' # version inference
} }
} }
# resource defined # resource defined
let(:resource_defined?) { true } let(:resource_defined?) { true }
let(:defined_serializer_class) { V1::UserSerializer } let(:defined_serializer_class) { V1::UserSerializer }
# options defined # options defined
let(:options_serializer_class) { V2::UserSerializer } let(:options_serializer_class) { V3::UserSerializer }
let(:serializer) { resolver.serializer } let(:serializer) { resolver.serializer }
@ -51,12 +52,55 @@ describe Grape::ActiveModelSerializers::SerializerResolver do
it 'returns serializer' do it 'returns serializer' do
expect(serializer).to be_kind_of(serializer_class) expect(serializer).to be_kind_of(serializer_class)
end end
context 'each serializer' do
let(:options) {
super().except(:serializer).merge(
each_serializer: V2::UserSerializer
)
}
let(:each_serializer) { serializer.send(:options)[:serializer] }
context 'each_serializer option' do
it 'returns expected serializer' do
expect(each_serializer).to eq(V2::UserSerializer)
end
end
context 'no each_serializer option' do
let(:options) { super().except(:each_serializer) }
context 'namespace inferred' do
it 'returns expected serializer' do
expect(each_serializer).to eq(V4::UserSerializer)
end
end
context 'not namespace inferred' do
let(:options) { super().except(:for) }
context 'version inferred' do
it 'returns expected serializer' do
expect(each_serializer).to eq(V5::UserSerializer)
end
end
context 'not version inferred' do
let(:options) { super().except(:version) }
it 'returns nil' do
expect(each_serializer).to eq(nil)
end
end
end
end
end
end end
context 'not resource collection' do context 'not resource collection' do
context 'specified by options' do context 'specified by options' do
it 'returns specified serializer' do it 'returns specified serializer' do
expect(serializer).to be_kind_of(V2::UserSerializer) expect(serializer).to be_kind_of(V3::UserSerializer)
end end
end end
@ -65,7 +109,7 @@ describe Grape::ActiveModelSerializers::SerializerResolver do
context 'namespace inferred' do context 'namespace inferred' do
it 'returns inferred serializer' do it 'returns inferred serializer' do
expect(serializer).to be_kind_of(V3::UserSerializer) expect(serializer).to be_kind_of(V4::UserSerializer)
end end
end end
@ -74,7 +118,7 @@ describe Grape::ActiveModelSerializers::SerializerResolver do
context 'version inferred' do context 'version inferred' do
it 'returns inferred serializer' do it 'returns inferred serializer' do
expect(serializer).to be_kind_of(V4::UserSerializer) expect(serializer).to be_kind_of(V5::UserSerializer)
end end
end end

View file

@ -1,4 +1,4 @@
module V3 module V4
class UsersApi < Grape::API class UsersApi < Grape::API
resource :users do resource :users do
desc 'all users' desc 'all users'

View file

@ -0,0 +1,5 @@
module V5
class UserSerializer < ActiveModel::Serializer
attributes :first_name, :last_name, :email
end
end