Refactor Association/Reflection block value reading

This commit is contained in:
Benjamin Fleischer 2015-12-03 10:53:43 -06:00
parent cd736e0adf
commit c4feccfd10
3 changed files with 35 additions and 24 deletions

View File

@ -12,11 +12,11 @@ module ActiveModel
DEFAULT_INCLUDE_TREE = ActiveModel::Serializer::IncludeTree.from_string('*')
included do |base|
base.class_attribute :serialized_associations, instance_writer: false # @api public: maps association name to 'Reflection' instance
base.serialized_associations ||= {}
base.class_attribute :_reflections, instance_writer: false
base._reflections ||= []
included do
with_options instance_writer: false, instance_reader: true do |serializer|
serializer.class_attribute :_reflections
self._reflections ||= []
end
extend ActiveSupport::Autoload
autoload :Association
@ -29,7 +29,6 @@ module ActiveModel
end
module ClassMethods
# Serializers inherit _reflections.
def inherited(base)
super
base._reflections = _reflections.dup
@ -43,7 +42,7 @@ module ActiveModel
# has_many :comments, serializer: CommentSummarySerializer
#
def has_many(name, options = {}, &block)
associate(HasManyReflection.new(name, options), block)
associate(HasManyReflection.new(name, options, block))
end
# @param [Symbol] name of the association
@ -54,7 +53,7 @@ module ActiveModel
# belongs_to :author, serializer: AuthorSerializer
#
def belongs_to(name, options = {}, &block)
associate(BelongsToReflection.new(name, options), block)
associate(BelongsToReflection.new(name, options, block))
end
# @param [Symbol] name of the association
@ -65,7 +64,7 @@ module ActiveModel
# has_one :author, serializer: AuthorSerializer
#
def has_one(name, options = {}, &block)
associate(HasOneReflection.new(name, options), block)
associate(HasOneReflection.new(name, options, block))
end
private
@ -76,20 +75,9 @@ module ActiveModel
#
# @api private
#
def associate(reflection, block)
def associate(reflection)
self._reflections = _reflections.dup
reflection_name = reflection.name
if block
serialized_associations[reflection_name] = ->(instance) { instance.instance_eval(&block) }
else
serialized_associations[reflection_name] = ->(instance) { instance.object.send(reflection_name) }
end
define_method reflection_name do
serialized_associations[reflection_name].call(self)
end unless method_defined?(reflection_name)
self._reflections << reflection
end
end

View File

@ -3,10 +3,12 @@ module ActiveModel
module Attributes
class Attribute
delegate :call, to: :reader
attr_reader :name, :reader
def initialize(name)
@name = name
@reader = nil
@reader = :no_reader
end
def self.build(name, block)

View File

@ -17,7 +17,28 @@ module ActiveModel
#
# So you can inspect reflections in your Adapters.
#
Reflection = Struct.new(:name, :options) do
Reflection = Struct.new(:name, :options, :block) do
delegate :call, to: :reader
attr_reader :reader
def initialize(*)
super
@reader = self.class.build_reader(name, block)
end
def value(instance)
call(instance)
end
def self.build_reader(name, block)
if block
->(instance) { instance.instance_eval(&block) }
else
->(instance) { instance.read_attribute_for_serialization(name) }
end
end
# Build association. This method is used internally to
# build serializer's association by its reflection.
#
@ -40,7 +61,7 @@ module ActiveModel
# @api private
#
def build_association(subject, parent_serializer_options)
association_value = subject.send(name)
association_value = value(subject)
reflection_options = options.dup
serializer_class = subject.class.serializer_for(association_value, reflection_options)