Skip to content

Commit

Permalink
Merge pull request #61 from drn/collection-serializer-support
Browse files Browse the repository at this point in the history
Implement support for collection serializers.
  • Loading branch information
dblock authored Jul 26, 2016
2 parents 2a4be72 + 6bb2057 commit eda39c5
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 23 deletions.
6 changes: 5 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

### 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).

### 1.4.0 (July 14, 2016)
Expand All @@ -11,8 +15,8 @@

### 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).
* [#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)

Expand Down
48 changes: 37 additions & 11 deletions lib/grape-active_model_serializers/serializer_resolver.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,40 @@ def initialize(resource, options)
end

def serializer
@serializer ||= (
serializer_class.new(resource, options) if serializer_class
)
serializer_class.new(resource, serializer_options) if serializer_class
end

private

attr_accessor :resource, :options

def serializer_class
serializer_class = resource_defined_class
serializer_class ||= collection_class
serializer_class ||= options[:serializer]
return @serializer_class if defined?(@serializer_class)
@serializer_class = resource_defined_class
@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 ||= version_inferred_class
serializer_class ||= resource_serializer_class
serializer_class
serializer_class ? { serializer: serializer_class } : {}
end

def resource_defined_class
Expand All @@ -36,12 +53,13 @@ def collection_class
end

def namespace_inferred_class
return nil unless options[:for]
return nil unless options.key?(:for)
namespace = options[:for].to_s.deconstantize
"#{namespace}::#{resource_serializer_klass}".safe_constantize
end

def version_inferred_class
return nil unless options.key?(:version)
"#{version}::#{resource_serializer_klass}".safe_constantize
end

Expand All @@ -57,14 +75,22 @@ def resource_serializer_klass
end

def resource_klass
resource.class.name.demodulize
resource_class.name.demodulize
end

def resource_namespace
klass = resource.class.name.deconstantize
klass = resource_class.name.deconstantize
klass.empty? ? nil : klass
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
ActiveModel::Serializer.serializer_for(resource)
end
Expand Down
64 changes: 54 additions & 10 deletions spec/grape/active_model_serializers/serializer_resolver_spec.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
require 'pry'
require 'spec_helper'

# asserts serializer resolution order:
# 1. resource_defined_class # V1::UserSerializer
# 2. collection_class # CollectionSerializer
# 3. options[:serializer] # V2::UserSerializer
# 4. namespace_inferred_class # V3::UserSerializer
# 5. version_inferred_class # V4::UserSerializer
# 2. collection_class # CollectionSerializer, V2::UserSerializer
# 3. options[:serializer] # V3::UserSerializer
# 4. namespace_inferred_class # V4::UserSerializer
# 5. version_inferred_class # V5::UserSerializer
# 6. resource_serializer_class # UserSerializer
# 7. missing resource # nil

Expand All @@ -15,15 +16,15 @@
let(:options) {
{
serializer: options_serializer_class, # options defined
for: V3::UsersApi, # namespace inference
version: 'v4' # version inference
for: V4::UsersApi, # namespace inference
version: 'v5' # version inference
}
}
# resource defined
let(:resource_defined?) { true }
let(:defined_serializer_class) { V1::UserSerializer }
# options defined
let(:options_serializer_class) { V2::UserSerializer }
let(:options_serializer_class) { V3::UserSerializer }

let(:serializer) { resolver.serializer }

Expand Down Expand Up @@ -51,12 +52,55 @@
it 'returns serializer' do
expect(serializer).to be_kind_of(serializer_class)
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

context 'not resource collection' do
context 'specified by options' do
it 'returns specified serializer' do
expect(serializer).to be_kind_of(V2::UserSerializer)
expect(serializer).to be_kind_of(V3::UserSerializer)
end
end

Expand All @@ -65,7 +109,7 @@

context 'namespace inferred' do
it 'returns inferred serializer' do
expect(serializer).to be_kind_of(V3::UserSerializer)
expect(serializer).to be_kind_of(V4::UserSerializer)
end
end

Expand All @@ -74,7 +118,7 @@

context 'version inferred' do
it 'returns inferred serializer' do
expect(serializer).to be_kind_of(V4::UserSerializer)
expect(serializer).to be_kind_of(V5::UserSerializer)
end
end

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module V3
module V4
class UsersApi < Grape::API
resource :users do
desc 'all users'
Expand Down
5 changes: 5 additions & 0 deletions spec/support/serializers/v5/user_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module V5
class UserSerializer < ActiveModel::Serializer
attributes :first_name, :last_name, :email
end
end

0 comments on commit eda39c5

Please sign in to comment.