Replace fail/rescue CollectionSerializer::NoSerializerError with throw/catch :no_serializer (#1767)

This commit is contained in:
Benjamin Fleischer 2016-09-26 09:18:27 -05:00 committed by L. Preston Sego III
parent c69855bfaa
commit 6c6e45b23f
5 changed files with 22 additions and 17 deletions

View File

@ -25,6 +25,8 @@ Fixes:
- [#1881](https://github.com/rails-api/active_model_serializers/pull/1881) ActiveModelSerializers::Model correctly works with string keys (@yevhene) - [#1881](https://github.com/rails-api/active_model_serializers/pull/1881) ActiveModelSerializers::Model correctly works with string keys (@yevhene)
Misc: Misc:
- [#1767](https://github.com/rails-api/active_model_serializers/pull/1767) Replace raising/rescuing `CollectionSerializer::NoSerializerError`,
throw/catch `:no_serializer`. (@bf4)
- [#1839](https://github.com/rails-api/active_model_serializers/pull/1839) `fields` tests demonstrating usage for both attributes and relationships. (@NullVoxPopuli) - [#1839](https://github.com/rails-api/active_model_serializers/pull/1839) `fields` tests demonstrating usage for both attributes and relationships. (@NullVoxPopuli)
- [#1812](https://github.com/rails-api/active_model_serializers/pull/1812) add a code of conduct (@corainchicago) - [#1812](https://github.com/rails-api/active_model_serializers/pull/1812) add a code of conduct (@corainchicago)

View File

@ -15,7 +15,7 @@ It requires an adapter to transform its attributes into a JSON document; it cann
It may be useful to think of it as a It may be useful to think of it as a
[presenter](http://blog.steveklabnik.com/posts/2011-09-09-better-ruby-presenters). [presenter](http://blog.steveklabnik.com/posts/2011-09-09-better-ruby-presenters).
The **`ActiveModel::ArraySerializer`** represent a collection of resources as serializers The **`ActiveModel::CollectionSerializer`** represents a collection of resources as serializers
and, if there is no serializer, primitives. and, if there is no serializer, primitives.
The **`ActiveModel::Adapter`** describes the structure of the JSON document generated from a The **`ActiveModel::Adapter`** describes the structure of the JSON document generated from a
@ -42,10 +42,9 @@ it is not modified.
Internally, if no serializer can be found in the controller, the resource is not decorated by Internally, if no serializer can be found in the controller, the resource is not decorated by
ActiveModelSerializers. ActiveModelSerializers.
If the collection serializer (ArraySerializer) cannot If the collection serializer (CollectionSerializer) cannot
identify a serializer for a resource in its collection, it raises [`NoSerializerError`](https://github.com/rails-api/active_model_serializers/issues/1191#issuecomment-142327128) identify a serializer for a resource in its collection, it throws [`:no_serializer`](https://github.com/rails-api/active_model_serializers/issues/1191#issuecomment-142327128).
which is rescued in `ActiveModel::Serializer::Reflection#build_association` which sets For example, when caught by `Reflection#build_association`, the association value is set directly:
the association value directly:
```ruby ```ruby
reflection_options[:virtual_value] = association_value.try(:as_json) || association_value reflection_options[:virtual_value] = association_value.try(:as_json) || association_value
@ -85,8 +84,8 @@ Details:
1. The serializer and adapter are created as 1. The serializer and adapter are created as
1. `serializer_instance = serializer.new(resource, serializer_opts)` 1. `serializer_instance = serializer.new(resource, serializer_opts)`
2. `adapter_instance = ActiveModel::Serializer::Adapter.create(serializer_instance, adapter_opts)` 2. `adapter_instance = ActiveModel::Serializer::Adapter.create(serializer_instance, adapter_opts)`
1. **ActiveModel::Serializer::ArraySerializer#new** 1. **ActiveModel::Serializer::CollectionSerializer#new**
1. If the `serializer_instance` was a `ArraySerializer` and the `:serializer` serializer_opts 1. If the `serializer_instance` was a `CollectionSerializer` and the `:serializer` serializer_opts
is present, then [that serializer is passed into each resource](https://github.com/rails-api/active_model_serializers/blob/a54d237e2828fe6bab1ea5dfe6360d4ecc8214cd/lib/active_model/serializer/array_serializer.rb#L14-L16). is present, then [that serializer is passed into each resource](https://github.com/rails-api/active_model_serializers/blob/a54d237e2828fe6bab1ea5dfe6360d4ecc8214cd/lib/active_model/serializer/array_serializer.rb#L14-L16).
1. **ActiveModel::Serializer#attributes** is used by the adapter to get the attributes for 1. **ActiveModel::Serializer#attributes** is used by the adapter to get the attributes for
resource as defined by the serializer. resource as defined by the serializer.

View File

@ -1,7 +1,6 @@
module ActiveModel module ActiveModel
class Serializer class Serializer
class CollectionSerializer class CollectionSerializer
NoSerializerError = Class.new(StandardError)
include Enumerable include Enumerable
delegate :each, to: :@serializers delegate :each, to: :@serializers
@ -74,8 +73,9 @@ module ActiveModel
def serializer_from_resource(resource, serializer_context_class, options) def serializer_from_resource(resource, serializer_context_class, options)
serializer_class = options.fetch(:serializer) { serializer_context_class.serializer_for(resource) } serializer_class = options.fetch(:serializer) { serializer_context_class.serializer_for(resource) }
if serializer_class.nil? # rubocop:disable Style/GuardClause if serializer_class.nil?
fail NoSerializerError, "No serializer found for resource: #{resource.inspect}" ActiveModelSerializers.logger.debug "No serializer found for resource: #{resource.inspect}"
throw :no_serializer
else else
serializer_class.new(resource, options.except(:serializer)) serializer_class.new(resource, options.except(:serializer))
end end

View File

@ -105,21 +105,24 @@ module ActiveModel
# @api private # @api private
# #
def build_association(parent_serializer, parent_serializer_options, include_slice = {}) def build_association(parent_serializer, parent_serializer_options, include_slice = {})
association_value = value(parent_serializer, include_slice)
reflection_options = options.dup reflection_options = options.dup
association_value = value(parent_serializer, include_slice)
serializer_class = parent_serializer.class.serializer_for(association_value, reflection_options) serializer_class = parent_serializer.class.serializer_for(association_value, reflection_options)
reflection_options[:include_data] = include_data?(include_slice) reflection_options[:include_data] = include_data?(include_slice)
reflection_options[:links] = @_links reflection_options[:links] = @_links
reflection_options[:meta] = @_meta reflection_options[:meta] = @_meta
if serializer_class if serializer_class
begin serializer = catch(:no_serializer) do
reflection_options[:serializer] = serializer_class.new( serializer_class.new(
association_value, association_value,
serializer_options(parent_serializer, parent_serializer_options, reflection_options) serializer_options(parent_serializer, parent_serializer_options, reflection_options)
) )
rescue ActiveModel::Serializer::CollectionSerializer::NoSerializerError end
if serializer.nil?
reflection_options[:virtual_value] = association_value.try(:as_json) || association_value reflection_options[:virtual_value] = association_value.try(:as_json) || association_value
else
reflection_options[:serializer] = serializer
end end
elsif !association_value.nil? && !association_value.instance_of?(Object) elsif !association_value.nil? && !association_value.instance_of?(Object)
reflection_options[:virtual_value] = association_value reflection_options[:virtual_value] = association_value

View File

@ -38,9 +38,10 @@ module ActiveModelSerializers
def find_adapter def find_adapter
return resource unless serializer? return resource unless serializer?
adapter = catch :no_serializer do
ActiveModelSerializers::Adapter.create(serializer_instance, adapter_opts) ActiveModelSerializers::Adapter.create(serializer_instance, adapter_opts)
rescue ActiveModel::Serializer::CollectionSerializer::NoSerializerError end
resource adapter || resource
end end
def serializer_instance def serializer_instance