diff --git a/lib/active_model/serializer/associations.rb b/lib/active_model/serializer/associations.rb index 0842b9c3..c4da3515 100644 --- a/lib/active_model/serializer/associations.rb +++ b/lib/active_model/serializer/associations.rb @@ -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 diff --git a/lib/active_model/serializer/attributes.rb b/lib/active_model/serializer/attributes.rb index bea270e7..f46b0f48 100644 --- a/lib/active_model/serializer/attributes.rb +++ b/lib/active_model/serializer/attributes.rb @@ -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) diff --git a/lib/active_model/serializer/reflection.rb b/lib/active_model/serializer/reflection.rb index 18850abe..e2d16d35 100644 --- a/lib/active_model/serializer/reflection.rb +++ b/lib/active_model/serializer/reflection.rb @@ -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)