mirror of
https://github.com/ditkrg/active_model_serializers.git
synced 2026-01-25 07:16:49 +00:00
Associations refactoring
* Move all associations related code from Serializer class to Associations module * Introduce Reflection class hierarchy * Introduce Association class * Rid off Serializer#each_association * Introduce Serializer#associations enumerator
This commit is contained in:
@@ -3,16 +3,18 @@ require 'thread_safe'
|
||||
module ActiveModel
|
||||
class Serializer
|
||||
extend ActiveSupport::Autoload
|
||||
|
||||
autoload :Configuration
|
||||
autoload :ArraySerializer
|
||||
autoload :Adapter
|
||||
autoload :Lint
|
||||
autoload :Associations
|
||||
include Configuration
|
||||
include Associations
|
||||
|
||||
class << self
|
||||
attr_accessor :_attributes
|
||||
attr_accessor :_attributes_keys
|
||||
attr_accessor :_associations
|
||||
attr_accessor :_urls
|
||||
attr_accessor :_cache
|
||||
attr_accessor :_fragmented
|
||||
@@ -24,12 +26,12 @@ module ActiveModel
|
||||
end
|
||||
|
||||
def self.inherited(base)
|
||||
base._attributes = self._attributes.try(:dup) || []
|
||||
base._attributes = self._attributes.try(:dup) || []
|
||||
base._attributes_keys = self._attributes_keys.try(:dup) || {}
|
||||
base._associations = self._associations.try(:dup) || {}
|
||||
base._urls = []
|
||||
serializer_file = File.open(caller.first[/^[^:]+/])
|
||||
base._cache_digest = Digest::MD5.hexdigest(serializer_file.read)
|
||||
super
|
||||
end
|
||||
|
||||
def self.attributes(*attrs)
|
||||
@@ -46,7 +48,7 @@ module ActiveModel
|
||||
|
||||
def self.attribute(attr, options = {})
|
||||
key = options.fetch(:key, attr)
|
||||
@_attributes_keys[attr] = {key: key} if key != attr
|
||||
@_attributes_keys[attr] = { key: key } if key != attr
|
||||
@_attributes << key unless @_attributes.include?(key)
|
||||
define_method key do
|
||||
object.read_attribute_for_serialization(attr)
|
||||
@@ -59,58 +61,13 @@ module ActiveModel
|
||||
|
||||
# Enables a serializer to be automatically cached
|
||||
def self.cache(options = {})
|
||||
@_cache = ActionController::Base.cache_store if Rails.configuration.action_controller.perform_caching
|
||||
@_cache_key = options.delete(:key)
|
||||
@_cache_only = options.delete(:only)
|
||||
@_cache_except = options.delete(:except)
|
||||
@_cache = ActionController::Base.cache_store if Rails.configuration.action_controller.perform_caching
|
||||
@_cache_key = options.delete(:key)
|
||||
@_cache_only = options.delete(:only)
|
||||
@_cache_except = options.delete(:except)
|
||||
@_cache_options = (options.empty?) ? nil : options
|
||||
end
|
||||
|
||||
# Defines an association in the object should be rendered.
|
||||
#
|
||||
# The serializer object should implement the association name
|
||||
# as a method which should return an array when invoked. If a method
|
||||
# with the association name does not exist, the association name is
|
||||
# dispatched to the serialized object.
|
||||
def self.has_many(*attrs)
|
||||
associate(:has_many, attrs)
|
||||
end
|
||||
|
||||
# Defines an association in the object that should be rendered.
|
||||
#
|
||||
# The serializer object should implement the association name
|
||||
# as a method which should return an object when invoked. If a method
|
||||
# with the association name does not exist, the association name is
|
||||
# dispatched to the serialized object.
|
||||
def self.belongs_to(*attrs)
|
||||
associate(:belongs_to, attrs)
|
||||
end
|
||||
|
||||
# Defines an association in the object should be rendered.
|
||||
#
|
||||
# The serializer object should implement the association name
|
||||
# as a method which should return an object when invoked. If a method
|
||||
# with the association name does not exist, the association name is
|
||||
# dispatched to the serialized object.
|
||||
def self.has_one(*attrs)
|
||||
associate(:has_one, attrs)
|
||||
end
|
||||
|
||||
def self.associate(type, attrs) #:nodoc:
|
||||
options = attrs.extract_options!
|
||||
self._associations = _associations.dup
|
||||
|
||||
attrs.each do |attr|
|
||||
unless method_defined?(attr)
|
||||
define_method attr do
|
||||
object.send attr
|
||||
end
|
||||
end
|
||||
|
||||
self._associations[attr] = {type: type, association_options: options}
|
||||
end
|
||||
end
|
||||
|
||||
def self.url(attr)
|
||||
@_urls.push attr
|
||||
end
|
||||
@@ -125,19 +82,17 @@ module ActiveModel
|
||||
elsif resource.respond_to?(:to_ary)
|
||||
config.array_serializer
|
||||
else
|
||||
options
|
||||
.fetch(:association_options, {})
|
||||
.fetch(:serializer, get_serializer_for(resource.class))
|
||||
options.fetch(:serializer, get_serializer_for(resource.class))
|
||||
end
|
||||
end
|
||||
|
||||
def self.adapter
|
||||
adapter_class = case config.adapter
|
||||
when Symbol
|
||||
ActiveModel::Serializer::Adapter.adapter_class(config.adapter)
|
||||
when Class
|
||||
config.adapter
|
||||
end
|
||||
when Symbol
|
||||
ActiveModel::Serializer::Adapter.adapter_class(config.adapter)
|
||||
when Class
|
||||
config.adapter
|
||||
end
|
||||
unless adapter_class
|
||||
valid_adapters = Adapter.constants.map { |klass| ":#{klass.to_s.downcase}" }
|
||||
raise ArgumentError, "Unknown adapter: #{config.adapter}. Valid adapters are: #{valid_adapters}"
|
||||
@@ -153,12 +108,12 @@ module ActiveModel
|
||||
attr_accessor :object, :root, :meta, :meta_key, :scope
|
||||
|
||||
def initialize(object, options = {})
|
||||
@object = object
|
||||
@options = options
|
||||
@root = options[:root]
|
||||
@meta = options[:meta]
|
||||
@meta_key = options[:meta_key]
|
||||
@scope = options[:scope]
|
||||
@object = object
|
||||
@options = options
|
||||
@root = options[:root]
|
||||
@meta = options[:meta]
|
||||
@meta_key = options[:meta_key]
|
||||
@scope = options[:scope]
|
||||
|
||||
scope_name = options[:scope_name]
|
||||
if scope_name && !respond_to?(scope_name)
|
||||
@@ -199,48 +154,10 @@ module ActiveModel
|
||||
end
|
||||
end
|
||||
|
||||
def each_association(&block)
|
||||
self.class._associations.dup.each do |name, association_options|
|
||||
next unless object
|
||||
association_value = send(name)
|
||||
|
||||
serializer_class = ActiveModel::Serializer.serializer_for(association_value, association_options)
|
||||
|
||||
if serializer_class
|
||||
begin
|
||||
serializer = serializer_class.new(
|
||||
association_value,
|
||||
options.except(:serializer).merge(serializer_from_options(association_options))
|
||||
)
|
||||
rescue ActiveModel::Serializer::ArraySerializer::NoSerializerError
|
||||
virtual_value = association_value
|
||||
virtual_value = virtual_value.as_json if virtual_value.respond_to?(:as_json)
|
||||
association_options[:association_options][:virtual_value] = virtual_value
|
||||
end
|
||||
elsif !association_value.nil? && !association_value.instance_of?(Object)
|
||||
association_options[:association_options][:virtual_value] = association_value
|
||||
end
|
||||
|
||||
association_key = association_options[:association_options][:key] || name
|
||||
if block_given?
|
||||
block.call(association_key, serializer, association_options[:association_options])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def serializer_from_options(options)
|
||||
opts = {}
|
||||
serializer = options.fetch(:association_options, {}).fetch(:serializer, nil)
|
||||
opts[:serializer] = serializer if serializer
|
||||
opts
|
||||
end
|
||||
|
||||
def self.serializers_cache
|
||||
@serializers_cache ||= ThreadSafe::Cache.new
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :options
|
||||
|
||||
def self.get_serializer_for(klass)
|
||||
@@ -255,6 +172,5 @@ module ActiveModel
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user