Make serializer lookup configurable (#1757)

This commit is contained in:
L. Preston Sego III
2016-11-16 12:38:40 -05:00
committed by Yohan Robert
parent d0de53cbb2
commit d31d741f43
10 changed files with 321 additions and 11 deletions

View File

@@ -60,17 +60,10 @@ module ActiveModel
# @api private
def self.serializer_lookup_chain_for(klass, namespace = nil)
chain = []
resource_class_name = klass.name.demodulize
resource_namespace = klass.name.deconstantize
serializer_class_name = "#{resource_class_name}Serializer"
chain.push("#{namespace}::#{serializer_class_name}") if namespace
chain.push("#{name}::#{serializer_class_name}") if self != ActiveModel::Serializer
chain.push("#{resource_namespace}::#{serializer_class_name}")
chain
lookups = ActiveModelSerializers.config.serializer_lookup_chain
Array[*lookups].flat_map do |lookup|
lookup.call(klass, self, namespace)
end.compact
end
# Used to cache serializer name => serializer class

View File

@@ -32,6 +32,26 @@ module ActiveModel
config.jsonapi_include_toplevel_object = false
config.include_data_default = true
# For configuring how serializers are found.
# This should be an array of procs.
#
# The priority of the output is that the first item
# in the evaluated result array will take precedence
# over other possible serializer paths.
#
# i.e.: First match wins.
#
# @example output
# => [
# "CustomNamespace::ResourceSerializer",
# "ParentSerializer::ResourceSerializer",
# "ResourceNamespace::ResourceSerializer" ,
# "ResourceSerializer"]
#
# If CustomNamespace::ResourceSerializer exists, it will be used
# for serialization
config.serializer_lookup_chain = ActiveModelSerializers::LookupChain::DEFAULT.dup
config.schema_path = 'test/support/schemas'
end
end

View File

@@ -14,6 +14,7 @@ module ActiveModelSerializers
autoload :Adapter
autoload :JsonPointer
autoload :Deprecate
autoload :LookupChain
class << self; attr_accessor :logger; end
self.logger = ActiveSupport::TaggedLogging.new(ActiveSupport::Logger.new(STDOUT))

View File

@@ -0,0 +1,80 @@
module ActiveModelSerializers
module LookupChain
# Standard appending of Serializer to the resource name.
#
# Example:
# Author => AuthorSerializer
BY_RESOURCE = lambda do |resource_class, _serializer_class, _namespace|
serializer_from(resource_class)
end
# Uses the namespace of the resource to find the serializer
#
# Example:
# British::Author => British::AuthorSerializer
BY_RESOURCE_NAMESPACE = lambda do |resource_class, _serializer_class, _namespace|
resource_namespace = namespace_for(resource_class)
serializer_name = serializer_from(resource_class)
"#{resource_namespace}::#{serializer_name}"
end
# Uses the controller namespace of the resource to find the serializer
#
# Example:
# Api::V3::AuthorsController => Api::V3::AuthorSerializer
BY_NAMESPACE = lambda do |resource_class, _serializer_class, namespace|
resource_name = resource_class_name(resource_class)
namespace ? "#{namespace}::#{resource_name}Serializer" : nil
end
# Allows for serializers to be defined in parent serializers
# - useful if a relationship only needs a different set of attributes
# than if it were rendered independently.
#
# Example:
# class BlogSerializer < ActiveModel::Serializer
# class AuthorSerialier < ActiveModel::Serializer
# ...
# end
#
# belongs_to :author
# ...
# end
#
# The belongs_to relationship would be rendered with
# BlogSerializer::AuthorSerialier
BY_PARENT_SERIALIZER = lambda do |resource_class, serializer_class, _namespace|
return if serializer_class == ActiveModel::Serializer
serializer_name = serializer_from(resource_class)
"#{serializer_class}::#{serializer_name}"
end
DEFAULT = [
BY_PARENT_SERIALIZER,
BY_NAMESPACE,
BY_RESOURCE_NAMESPACE,
BY_RESOURCE
].freeze
module_function
def namespace_for(klass)
klass.name.deconstantize
end
def resource_class_name(klass)
klass.name.demodulize
end
def serializer_from_resource_name(name)
"#{name}Serializer"
end
def serializer_from(klass)
name = resource_class_name(klass)
serializer_from_resource_name(name)
end
end
end