Skip to content

Commit c4feccf

Browse files
committed
Refactor Association/Reflection block value reading
1 parent cd736e0 commit c4feccf

File tree

3 files changed

+35
-24
lines changed

3 files changed

+35
-24
lines changed

lib/active_model/serializer/associations.rb

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@ module Associations
1212

1313
DEFAULT_INCLUDE_TREE = ActiveModel::Serializer::IncludeTree.from_string('*')
1414

15-
included do |base|
16-
base.class_attribute :serialized_associations, instance_writer: false # @api public: maps association name to 'Reflection' instance
17-
base.serialized_associations ||= {}
18-
base.class_attribute :_reflections, instance_writer: false
19-
base._reflections ||= []
15+
included do
16+
with_options instance_writer: false, instance_reader: true do |serializer|
17+
serializer.class_attribute :_reflections
18+
self._reflections ||= []
19+
end
2020

2121
extend ActiveSupport::Autoload
2222
autoload :Association
@@ -29,7 +29,6 @@ module Associations
2929
end
3030

3131
module ClassMethods
32-
# Serializers inherit _reflections.
3332
def inherited(base)
3433
super
3534
base._reflections = _reflections.dup
@@ -43,7 +42,7 @@ def inherited(base)
4342
# has_many :comments, serializer: CommentSummarySerializer
4443
#
4544
def has_many(name, options = {}, &block)
46-
associate(HasManyReflection.new(name, options), block)
45+
associate(HasManyReflection.new(name, options, block))
4746
end
4847

4948
# @param [Symbol] name of the association
@@ -54,7 +53,7 @@ def has_many(name, options = {}, &block)
5453
# belongs_to :author, serializer: AuthorSerializer
5554
#
5655
def belongs_to(name, options = {}, &block)
57-
associate(BelongsToReflection.new(name, options), block)
56+
associate(BelongsToReflection.new(name, options, block))
5857
end
5958

6059
# @param [Symbol] name of the association
@@ -65,7 +64,7 @@ def belongs_to(name, options = {}, &block)
6564
# has_one :author, serializer: AuthorSerializer
6665
#
6766
def has_one(name, options = {}, &block)
68-
associate(HasOneReflection.new(name, options), block)
67+
associate(HasOneReflection.new(name, options, block))
6968
end
7069

7170
private
@@ -76,20 +75,9 @@ def has_one(name, options = {}, &block)
7675
#
7776
# @api private
7877
#
79-
def associate(reflection, block)
78+
def associate(reflection)
8079
self._reflections = _reflections.dup
8180

82-
reflection_name = reflection.name
83-
if block
84-
serialized_associations[reflection_name] = ->(instance) { instance.instance_eval(&block) }
85-
else
86-
serialized_associations[reflection_name] = ->(instance) { instance.object.send(reflection_name) }
87-
end
88-
89-
define_method reflection_name do
90-
serialized_associations[reflection_name].call(self)
91-
end unless method_defined?(reflection_name)
92-
9381
self._reflections << reflection
9482
end
9583
end

lib/active_model/serializer/attributes.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@ class Serializer
33
module Attributes
44
class Attribute
55
delegate :call, to: :reader
6+
67
attr_reader :name, :reader
8+
79
def initialize(name)
810
@name = name
9-
@reader = nil
11+
@reader = :no_reader
1012
end
1113

1214
def self.build(name, block)

lib/active_model/serializer/reflection.rb

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,28 @@ class Serializer
1717
#
1818
# So you can inspect reflections in your Adapters.
1919
#
20-
Reflection = Struct.new(:name, :options) do
20+
Reflection = Struct.new(:name, :options, :block) do
21+
delegate :call, to: :reader
22+
23+
attr_reader :reader
24+
25+
def initialize(*)
26+
super
27+
@reader = self.class.build_reader(name, block)
28+
end
29+
30+
def value(instance)
31+
call(instance)
32+
end
33+
34+
def self.build_reader(name, block)
35+
if block
36+
->(instance) { instance.instance_eval(&block) }
37+
else
38+
->(instance) { instance.read_attribute_for_serialization(name) }
39+
end
40+
end
41+
2142
# Build association. This method is used internally to
2243
# build serializer's association by its reflection.
2344
#
@@ -40,7 +61,7 @@ class Serializer
4061
# @api private
4162
#
4263
def build_association(subject, parent_serializer_options)
43-
association_value = subject.send(name)
64+
association_value = value(subject)
4465
reflection_options = options.dup
4566
serializer_class = subject.class.serializer_for(association_value, reflection_options)
4667

0 commit comments

Comments
 (0)