active_model_serializers 0.10.0 → 0.10.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. checksums.yaml +5 -5
  2. data/.rubocop.yml +6 -5
  3. data/.travis.yml +30 -21
  4. data/CHANGELOG.md +172 -2
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +23 -4
  7. data/README.md +166 -28
  8. data/Rakefile +3 -32
  9. data/active_model_serializers.gemspec +22 -25
  10. data/appveyor.yml +10 -6
  11. data/bin/rubocop +38 -0
  12. data/docs/README.md +2 -1
  13. data/docs/general/adapters.md +35 -11
  14. data/docs/general/caching.md +7 -1
  15. data/docs/general/configuration_options.md +86 -1
  16. data/docs/general/deserialization.md +1 -1
  17. data/docs/general/fields.md +31 -0
  18. data/docs/general/getting_started.md +1 -1
  19. data/docs/general/logging.md +7 -0
  20. data/docs/general/rendering.md +63 -25
  21. data/docs/general/serializers.md +125 -14
  22. data/docs/howto/add_pagination_links.md +16 -17
  23. data/docs/howto/add_relationship_links.md +140 -0
  24. data/docs/howto/add_root_key.md +11 -0
  25. data/docs/howto/grape_integration.md +42 -0
  26. data/docs/howto/outside_controller_use.md +12 -4
  27. data/docs/howto/passing_arbitrary_options.md +2 -2
  28. data/docs/howto/serialize_poro.md +46 -5
  29. data/docs/howto/test.md +2 -0
  30. data/docs/howto/upgrade_from_0_8_to_0_10.md +265 -0
  31. data/docs/integrations/ember-and-json-api.md +67 -32
  32. data/docs/jsonapi/schema.md +1 -1
  33. data/lib/action_controller/serialization.rb +13 -3
  34. data/lib/active_model/serializer/adapter/base.rb +2 -0
  35. data/lib/active_model/serializer/array_serializer.rb +8 -5
  36. data/lib/active_model/serializer/association.rb +62 -10
  37. data/lib/active_model/serializer/belongs_to_reflection.rb +4 -3
  38. data/lib/active_model/serializer/collection_serializer.rb +39 -13
  39. data/lib/active_model/serializer/{caching.rb → concerns/caching.rb} +82 -115
  40. data/lib/active_model/serializer/error_serializer.rb +11 -7
  41. data/lib/active_model/serializer/errors_serializer.rb +25 -20
  42. data/lib/active_model/serializer/has_many_reflection.rb +3 -3
  43. data/lib/active_model/serializer/has_one_reflection.rb +1 -4
  44. data/lib/active_model/serializer/lazy_association.rb +95 -0
  45. data/lib/active_model/serializer/lint.rb +134 -130
  46. data/lib/active_model/serializer/reflection.rb +127 -67
  47. data/lib/active_model/serializer/version.rb +1 -1
  48. data/lib/active_model/serializer.rb +297 -79
  49. data/lib/active_model_serializers/adapter/attributes.rb +3 -66
  50. data/lib/active_model_serializers/adapter/base.rb +39 -39
  51. data/lib/active_model_serializers/adapter/json_api/deserialization.rb +2 -2
  52. data/lib/active_model_serializers/adapter/json_api/link.rb +1 -1
  53. data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +47 -21
  54. data/lib/active_model_serializers/adapter/json_api/relationship.rb +75 -23
  55. data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +39 -10
  56. data/lib/active_model_serializers/adapter/json_api.rb +71 -57
  57. data/lib/active_model_serializers/adapter.rb +6 -0
  58. data/lib/active_model_serializers/deprecate.rb +1 -2
  59. data/lib/active_model_serializers/deserialization.rb +2 -0
  60. data/lib/active_model_serializers/lookup_chain.rb +80 -0
  61. data/lib/active_model_serializers/model.rb +109 -28
  62. data/lib/active_model_serializers/railtie.rb +3 -1
  63. data/lib/active_model_serializers/register_jsonapi_renderer.rb +44 -31
  64. data/lib/active_model_serializers/serializable_resource.rb +6 -5
  65. data/lib/active_model_serializers/serialization_context.rb +10 -3
  66. data/lib/active_model_serializers/test/schema.rb +2 -2
  67. data/lib/active_model_serializers.rb +16 -1
  68. data/lib/generators/rails/resource_override.rb +1 -1
  69. data/lib/generators/rails/serializer_generator.rb +4 -4
  70. data/lib/grape/active_model_serializers.rb +7 -5
  71. data/lib/grape/formatters/active_model_serializers.rb +19 -2
  72. data/lib/grape/helpers/active_model_serializers.rb +1 -0
  73. data/lib/tasks/rubocop.rake +53 -0
  74. data/test/action_controller/adapter_selector_test.rb +14 -5
  75. data/test/action_controller/explicit_serializer_test.rb +5 -4
  76. data/test/action_controller/json/include_test.rb +106 -27
  77. data/test/action_controller/json_api/deserialization_test.rb +1 -1
  78. data/test/action_controller/json_api/errors_test.rb +8 -9
  79. data/test/action_controller/json_api/fields_test.rb +66 -0
  80. data/test/action_controller/json_api/linked_test.rb +29 -24
  81. data/test/action_controller/json_api/pagination_test.rb +31 -23
  82. data/test/action_controller/json_api/transform_test.rb +11 -3
  83. data/test/action_controller/lookup_proc_test.rb +49 -0
  84. data/test/action_controller/namespace_lookup_test.rb +232 -0
  85. data/test/action_controller/serialization_scope_name_test.rb +12 -6
  86. data/test/action_controller/serialization_test.rb +12 -9
  87. data/test/active_model_serializers/json_pointer_test.rb +15 -13
  88. data/test/active_model_serializers/model_test.rb +137 -4
  89. data/test/active_model_serializers/railtie_test_isolated.rb +12 -7
  90. data/test/active_model_serializers/register_jsonapi_renderer_test_isolated.rb +161 -0
  91. data/test/active_model_serializers/serialization_context_test_isolated.rb +23 -10
  92. data/test/active_model_serializers/test/schema_test.rb +3 -2
  93. data/test/adapter/attributes_test.rb +40 -0
  94. data/test/adapter/json/collection_test.rb +14 -0
  95. data/test/adapter/json/has_many_test.rb +10 -2
  96. data/test/adapter/json/transform_test.rb +15 -15
  97. data/test/adapter/json_api/collection_test.rb +4 -3
  98. data/test/adapter/json_api/errors_test.rb +17 -19
  99. data/test/adapter/json_api/fields_test.rb +12 -3
  100. data/test/adapter/json_api/has_many_test.rb +49 -20
  101. data/test/adapter/json_api/include_data_if_sideloaded_test.rb +213 -0
  102. data/test/adapter/json_api/json_api_test.rb +5 -7
  103. data/test/adapter/json_api/linked_test.rb +33 -12
  104. data/test/adapter/json_api/links_test.rb +4 -2
  105. data/test/adapter/json_api/pagination_links_test.rb +53 -13
  106. data/test/adapter/json_api/parse_test.rb +1 -1
  107. data/test/adapter/json_api/relationship_test.rb +309 -73
  108. data/test/adapter/json_api/resource_meta_test.rb +3 -3
  109. data/test/adapter/json_api/transform_test.rb +263 -253
  110. data/test/adapter/json_api/type_test.rb +168 -36
  111. data/test/adapter/json_test.rb +8 -7
  112. data/test/adapter/null_test.rb +1 -2
  113. data/test/adapter/polymorphic_test.rb +52 -5
  114. data/test/adapter_test.rb +1 -1
  115. data/test/benchmark/app.rb +1 -1
  116. data/test/benchmark/benchmarking_support.rb +1 -1
  117. data/test/benchmark/bm_active_record.rb +81 -0
  118. data/test/benchmark/bm_adapter.rb +38 -0
  119. data/test/benchmark/bm_caching.rb +16 -16
  120. data/test/benchmark/bm_lookup_chain.rb +83 -0
  121. data/test/benchmark/bm_transform.rb +21 -10
  122. data/test/benchmark/controllers.rb +16 -17
  123. data/test/benchmark/fixtures.rb +72 -72
  124. data/test/cache_test.rb +235 -69
  125. data/test/collection_serializer_test.rb +31 -14
  126. data/test/fixtures/active_record.rb +45 -10
  127. data/test/fixtures/poro.rb +124 -181
  128. data/test/generators/serializer_generator_test.rb +23 -5
  129. data/test/grape_test.rb +170 -56
  130. data/test/lint_test.rb +1 -1
  131. data/test/logger_test.rb +13 -11
  132. data/test/serializable_resource_test.rb +18 -22
  133. data/test/serializers/association_macros_test.rb +3 -2
  134. data/test/serializers/associations_test.rb +222 -49
  135. data/test/serializers/attribute_test.rb +5 -3
  136. data/test/serializers/attributes_test.rb +1 -1
  137. data/test/serializers/caching_configuration_test_isolated.rb +6 -6
  138. data/test/serializers/fieldset_test.rb +1 -1
  139. data/test/serializers/meta_test.rb +12 -6
  140. data/test/serializers/options_test.rb +17 -6
  141. data/test/serializers/read_attribute_for_serialization_test.rb +3 -3
  142. data/test/serializers/reflection_test.rb +427 -0
  143. data/test/serializers/root_test.rb +1 -1
  144. data/test/serializers/serialization_test.rb +2 -2
  145. data/test/serializers/serializer_for_test.rb +12 -10
  146. data/test/serializers/serializer_for_with_namespace_test.rb +88 -0
  147. data/test/support/isolated_unit.rb +9 -4
  148. data/test/support/rails5_shims.rb +8 -2
  149. data/test/support/rails_app.rb +2 -9
  150. data/test/support/serialization_testing.rb +31 -5
  151. data/test/test_helper.rb +13 -0
  152. metadata +130 -71
  153. data/.rubocop_todo.yml +0 -167
  154. data/docs/ARCHITECTURE.md +0 -126
  155. data/lib/active_model/serializer/associations.rb +0 -100
  156. data/lib/active_model/serializer/attributes.rb +0 -82
  157. data/lib/active_model/serializer/collection_reflection.rb +0 -7
  158. data/lib/active_model/serializer/configuration.rb +0 -35
  159. data/lib/active_model/serializer/include_tree.rb +0 -111
  160. data/lib/active_model/serializer/links.rb +0 -35
  161. data/lib/active_model/serializer/meta.rb +0 -29
  162. data/lib/active_model/serializer/singular_reflection.rb +0 -7
  163. data/lib/active_model/serializer/type.rb +0 -25
  164. data/lib/active_model_serializers/key_transform.rb +0 -70
  165. data/test/active_model_serializers/key_transform_test.rb +0 -263
  166. data/test/adapter/json_api/has_many_embed_ids_test.rb +0 -43
  167. data/test/adapter/json_api/relationships_test.rb +0 -199
  168. data/test/adapter/json_api/resource_identifier_test.rb +0 -85
  169. data/test/include_tree/from_include_args_test.rb +0 -26
  170. data/test/include_tree/from_string_test.rb +0 -94
  171. data/test/include_tree/include_args_to_hash_test.rb +0 -64
@@ -15,7 +15,8 @@ module ActiveModel
15
15
  @blog,
16
16
  adapter: :json,
17
17
  serializer: AlternateBlogSerializer,
18
- meta: { total: 10 }).as_json
18
+ meta: { total: 10 }
19
+ ).as_json
19
20
  expected = {
20
21
  blog: {
21
22
  id: 1,
@@ -65,7 +66,8 @@ module ActiveModel
65
66
  @blog,
66
67
  adapter: :attributes,
67
68
  serializer: AlternateBlogSerializer,
68
- meta: { total: 10 }).as_json
69
+ meta: { total: 10 }
70
+ ).as_json
69
71
  expected = {
70
72
  id: 1,
71
73
  title: 'AMS Hints'
@@ -79,7 +81,8 @@ module ActiveModel
79
81
  adapter: :json,
80
82
  serializer: AlternateBlogSerializer,
81
83
  meta: { total: 10 },
82
- meta_key: 'haha_meta').as_json
84
+ meta_key: 'haha_meta'
85
+ ).as_json
83
86
  expected = {
84
87
  blog: {
85
88
  id: 1,
@@ -98,7 +101,8 @@ module ActiveModel
98
101
  adapter: :json_api,
99
102
  serializer: AlternateBlogSerializer,
100
103
  meta: { total: 10 },
101
- meta_key: 'haha_meta').as_json
104
+ meta_key: 'haha_meta'
105
+ ).as_json
102
106
  expected = {
103
107
  data: {
104
108
  id: '1',
@@ -148,7 +152,8 @@ module ActiveModel
148
152
  actual = ActiveModelSerializers::SerializableResource.new(
149
153
  [@blog],
150
154
  adapter: :attributes,
151
- meta: { total: 10 }).as_json
155
+ meta: { total: 10 }
156
+ ).as_json
152
157
  expected = [{
153
158
  id: 1,
154
159
  name: 'AMS Hints',
@@ -170,7 +175,8 @@ module ActiveModel
170
175
  [@blog],
171
176
  adapter: :json,
172
177
  meta: { total: 10 },
173
- meta_key: 'haha_meta').as_json
178
+ meta_key: 'haha_meta'
179
+ ).as_json
174
180
  expected = {
175
181
  blogs: [{
176
182
  id: 1,
@@ -3,18 +3,29 @@ require 'test_helper'
3
3
  module ActiveModel
4
4
  class Serializer
5
5
  class OptionsTest < ActiveSupport::TestCase
6
- def setup
7
- @profile = Profile.new(name: 'Name 1', description: 'Description 1')
6
+ class ModelWithOptions < ActiveModelSerializers::Model
7
+ attributes :name, :description
8
+ end
9
+ class ModelWithOptionsSerializer < ActiveModel::Serializer
10
+ attributes :name, :description
11
+
12
+ def arguments_passed_in?
13
+ instance_options[:my_options] == :accessible
14
+ end
15
+ end
16
+
17
+ setup do
18
+ @model_with_options = ModelWithOptions.new(name: 'Name 1', description: 'Description 1')
8
19
  end
9
20
 
10
21
  def test_options_are_accessible
11
- @profile_serializer = ProfileSerializer.new(@profile, my_options: :accessible)
12
- assert @profile_serializer.arguments_passed_in?
22
+ model_with_options_serializer = ModelWithOptionsSerializer.new(@model_with_options, my_options: :accessible)
23
+ assert model_with_options_serializer.arguments_passed_in?
13
24
  end
14
25
 
15
26
  def test_no_option_is_passed_in
16
- @profile_serializer = ProfileSerializer.new(@profile)
17
- refute @profile_serializer.arguments_passed_in?
27
+ model_with_options_serializer = ModelWithOptionsSerializer.new(@model_with_options)
28
+ refute model_with_options_serializer.arguments_passed_in?
18
29
  end
19
30
  end
20
31
  end
@@ -5,10 +5,10 @@ module ActiveModel
5
5
  class ReadAttributeForSerializationTest < ActiveSupport::TestCase
6
6
  # https://github.com/rails-api/active_model_serializers/issues/1653
7
7
  class Parent < ActiveModelSerializers::Model
8
- attr_accessor :id
8
+ attributes :id
9
9
  end
10
10
  class Child < Parent
11
- attr_accessor :name
11
+ attributes :name
12
12
  end
13
13
  class ParentSerializer < ActiveModel::Serializer
14
14
  attributes :$id
@@ -30,7 +30,7 @@ module ActiveModel
30
30
 
31
31
  # https://github.com/rails-api/active_model_serializers/issues/1658
32
32
  class ErrorResponse < ActiveModelSerializers::Model
33
- attr_accessor :error
33
+ attributes :error
34
34
  end
35
35
  class ApplicationSerializer < ActiveModel::Serializer
36
36
  attributes :status
@@ -0,0 +1,427 @@
1
+ require 'test_helper'
2
+ module ActiveModel
3
+ class Serializer
4
+ class ReflectionTest < ActiveSupport::TestCase
5
+ class Blog < ActiveModelSerializers::Model
6
+ attributes :id
7
+ end
8
+ class BlogSerializer < ActiveModel::Serializer
9
+ type 'blog'
10
+ attributes :id
11
+ end
12
+
13
+ setup do
14
+ @expected_meta = { id: 1 }
15
+ @expected_links = { self: 'no_uri_validation' }
16
+ @empty_links = {}
17
+ model_attributes = { blog: Blog.new(@expected_meta) }
18
+ @model = Class.new(ActiveModelSerializers::Model) do
19
+ attributes(*model_attributes.keys)
20
+
21
+ def self.name
22
+ 'TestModel'
23
+ end
24
+ end.new(model_attributes)
25
+ @instance_options = {}
26
+ end
27
+
28
+ def evaluate_association_value(association)
29
+ association.lazy_association.eval_reflection_block
30
+ end
31
+
32
+ # TODO: Remaining tests
33
+ # test_reflection_value_block_with_scope
34
+ # test_reflection_value_uses_serializer_instance_method
35
+ # test_reflection_excluded_eh_blank_is_false
36
+ # test_reflection_excluded_eh_if
37
+ # test_reflection_excluded_eh_unless
38
+ # test_evaluate_condition_symbol_serializer_method
39
+ # test_evaluate_condition_string_serializer_method
40
+ # test_evaluate_condition_proc
41
+ # test_evaluate_condition_proc_yields_serializer
42
+ # test_evaluate_condition_other
43
+ # test_options_key
44
+ # test_options_polymorphic
45
+ # test_options_serializer
46
+ # test_options_virtual_value
47
+ # test_options_namespace
48
+
49
+ def test_reflection_value
50
+ serializer_class = Class.new(ActiveModel::Serializer) do
51
+ has_one :blog
52
+ end
53
+ serializer_instance = serializer_class.new(@model, @instance_options)
54
+
55
+ # Get Reflection
56
+ reflection = serializer_class._reflections.fetch(:blog)
57
+
58
+ # Assert
59
+ assert_nil reflection.block
60
+ assert_equal Serializer.config.include_data_default, reflection.options.fetch(:include_data_setting)
61
+ assert_equal true, reflection.options.fetch(:include_data_setting)
62
+
63
+ include_slice = :does_not_matter
64
+ assert_equal @model.blog, reflection.send(:value, serializer_instance, include_slice)
65
+ end
66
+
67
+ def test_reflection_value_block
68
+ serializer_class = Class.new(ActiveModel::Serializer) do
69
+ has_one :blog do
70
+ object.blog
71
+ end
72
+ end
73
+ serializer_instance = serializer_class.new(@model, @instance_options)
74
+
75
+ # Get Reflection
76
+ reflection = serializer_class._reflections.fetch(:blog)
77
+
78
+ # Assert
79
+ assert_respond_to reflection.block, :call
80
+ assert_equal Serializer.config.include_data_default, reflection.options.fetch(:include_data_setting)
81
+ assert_equal true, reflection.options.fetch(:include_data_setting)
82
+
83
+ include_slice = :does_not_matter
84
+ assert_equal @model.blog, reflection.send(:value, serializer_instance, include_slice)
85
+ end
86
+
87
+ def test_reflection_value_block_with_explicit_include_data_true
88
+ serializer_class = Class.new(ActiveModel::Serializer) do
89
+ has_one :blog do
90
+ include_data true
91
+ object.blog
92
+ end
93
+ end
94
+ serializer_instance = serializer_class.new(@model, @instance_options)
95
+
96
+ # Get Reflection
97
+ reflection = serializer_class._reflections.fetch(:blog)
98
+
99
+ # Assert
100
+ assert_respond_to reflection.block, :call
101
+ assert_equal Serializer.config.include_data_default, reflection.options.fetch(:include_data_setting)
102
+ assert_equal true, reflection.options.fetch(:include_data_setting)
103
+
104
+ include_slice = :does_not_matter
105
+ assert_equal @model.blog, reflection.send(:value, serializer_instance, include_slice)
106
+ end
107
+
108
+ def test_reflection_value_block_with_include_data_false_mutates_the_reflection_include_data
109
+ serializer_class = Class.new(ActiveModel::Serializer) do
110
+ has_one :blog do
111
+ include_data false
112
+ object.blog
113
+ end
114
+ end
115
+ serializer_instance = serializer_class.new(@model, @instance_options)
116
+
117
+ # Get Reflection
118
+ reflection = serializer_class._reflections.fetch(:blog)
119
+
120
+ # Assert
121
+ assert_respond_to reflection.block, :call
122
+ assert_equal true, reflection.options.fetch(:include_data_setting)
123
+ include_slice = :does_not_matter
124
+ assert_nil reflection.send(:value, serializer_instance, include_slice)
125
+ assert_equal false, reflection.options.fetch(:include_data_setting)
126
+ end
127
+
128
+ def test_reflection_value_block_with_include_data_if_sideloaded_included_mutates_the_reflection_include_data
129
+ serializer_class = Class.new(ActiveModel::Serializer) do
130
+ has_one :blog do
131
+ include_data :if_sideloaded
132
+ object.blog
133
+ end
134
+ end
135
+ serializer_instance = serializer_class.new(@model, @instance_options)
136
+
137
+ # Get Reflection
138
+ reflection = serializer_class._reflections.fetch(:blog)
139
+
140
+ # Assert
141
+ assert_respond_to reflection.block, :call
142
+ assert_equal true, reflection.options.fetch(:include_data_setting)
143
+ include_slice = {}
144
+ assert_nil reflection.send(:value, serializer_instance, include_slice)
145
+ assert_equal :if_sideloaded, reflection.options.fetch(:include_data_setting)
146
+ end
147
+
148
+ def test_reflection_value_block_with_include_data_if_sideloaded_excluded_mutates_the_reflection_include_data
149
+ serializer_class = Class.new(ActiveModel::Serializer) do
150
+ has_one :blog do
151
+ include_data :if_sideloaded
152
+ object.blog
153
+ end
154
+ end
155
+ serializer_instance = serializer_class.new(@model, @instance_options)
156
+
157
+ # Get Reflection
158
+ reflection = serializer_class._reflections.fetch(:blog)
159
+
160
+ # Assert
161
+ assert_respond_to reflection.block, :call
162
+ assert_equal true, reflection.options.fetch(:include_data_setting)
163
+ include_slice = { blog: :does_not_matter }
164
+ assert_equal @model.blog, reflection.send(:value, serializer_instance, include_slice)
165
+ assert_equal :if_sideloaded, reflection.options.fetch(:include_data_setting)
166
+ end
167
+
168
+ def test_reflection_block_with_link_mutates_the_reflection_links
169
+ serializer_class = Class.new(ActiveModel::Serializer) do
170
+ has_one :blog do
171
+ link :self, 'no_uri_validation'
172
+ end
173
+ end
174
+ serializer_instance = serializer_class.new(@model, @instance_options)
175
+
176
+ # Get Reflection
177
+ reflection = serializer_class._reflections.fetch(:blog)
178
+ assert_equal @empty_links, reflection.options.fetch(:links)
179
+
180
+ # Build Association
181
+ association = reflection.build_association(serializer_instance, @instance_options)
182
+
183
+ # Assert association links empty when not yet evaluated
184
+ assert_equal @empty_links, reflection.options.fetch(:links)
185
+ assert_equal @empty_links, association.links
186
+
187
+ evaluate_association_value(association)
188
+
189
+ assert_equal @expected_links, association.links
190
+ assert_equal @expected_links, reflection.options.fetch(:links)
191
+ end
192
+
193
+ def test_reflection_block_with_link_block_mutates_the_reflection_links
194
+ serializer_class = Class.new(ActiveModel::Serializer) do
195
+ has_one :blog do
196
+ link :self do
197
+ 'no_uri_validation'
198
+ end
199
+ end
200
+ end
201
+ serializer_instance = serializer_class.new(@model, @instance_options)
202
+
203
+ # Get Reflection
204
+ reflection = serializer_class._reflections.fetch(:blog)
205
+ assert_equal @empty_links, reflection.options.fetch(:links)
206
+
207
+ # Build Association
208
+ association = reflection.build_association(serializer_instance, @instance_options)
209
+
210
+ # Assert association links empty when not yet evaluated
211
+ assert_equal @empty_links, association.links
212
+
213
+ evaluate_association_value(association)
214
+
215
+ # Assert before instance_eval link
216
+ link = association.links.fetch(:self)
217
+ assert_respond_to link, :call
218
+ assert_respond_to reflection.options.fetch(:links).fetch(:self), :call
219
+
220
+ # Assert after instance_eval link
221
+ assert_equal @expected_links.fetch(:self), reflection.instance_eval(&link)
222
+ assert_respond_to reflection.options.fetch(:links).fetch(:self), :call
223
+ end
224
+
225
+ def test_reflection_block_with_meta_mutates_the_reflection_meta
226
+ serializer_class = Class.new(ActiveModel::Serializer) do
227
+ has_one :blog do
228
+ meta(id: object.blog.id)
229
+ end
230
+ end
231
+ serializer_instance = serializer_class.new(@model, @instance_options)
232
+
233
+ # Get Reflection
234
+ reflection = serializer_class._reflections.fetch(:blog)
235
+ assert_nil reflection.options.fetch(:meta)
236
+
237
+ # Build Association
238
+ association = reflection.build_association(serializer_instance, @instance_options)
239
+
240
+ evaluate_association_value(association)
241
+
242
+ assert_equal @expected_meta, association.meta
243
+ assert_equal @expected_meta, reflection.options.fetch(:meta)
244
+ end
245
+
246
+ def test_reflection_block_with_meta_block_mutates_the_reflection_meta
247
+ serializer_class = Class.new(ActiveModel::Serializer) do
248
+ has_one :blog do
249
+ meta do
250
+ { id: object.blog.id }
251
+ end
252
+ end
253
+ end
254
+ serializer_instance = serializer_class.new(@model, @instance_options)
255
+
256
+ # Get Reflection
257
+ reflection = serializer_class._reflections.fetch(:blog)
258
+ assert_nil reflection.options.fetch(:meta)
259
+
260
+ # Build Association
261
+ association = reflection.build_association(serializer_instance, @instance_options)
262
+ # Assert before instance_eval meta
263
+
264
+ evaluate_association_value(association)
265
+
266
+ assert_respond_to association.meta, :call
267
+ assert_respond_to reflection.options.fetch(:meta), :call
268
+
269
+ # Assert after instance_eval meta
270
+ assert_equal @expected_meta, reflection.instance_eval(&association.meta)
271
+ assert_respond_to reflection.options.fetch(:meta), :call
272
+ assert_respond_to association.meta, :call
273
+ end
274
+
275
+ # rubocop:disable Metrics/AbcSize
276
+ def test_reflection_block_with_meta_in_link_block_mutates_the_reflection_meta
277
+ serializer_class = Class.new(ActiveModel::Serializer) do
278
+ has_one :blog do
279
+ link :self do
280
+ meta(id: object.blog.id)
281
+ 'no_uri_validation'
282
+ end
283
+ end
284
+ end
285
+ serializer_instance = serializer_class.new(@model, @instance_options)
286
+
287
+ # Get Reflection
288
+ reflection = serializer_class._reflections.fetch(:blog)
289
+ assert_nil reflection.options.fetch(:meta)
290
+ assert_equal @empty_links, reflection.options.fetch(:links)
291
+
292
+ # Build Association
293
+ association = reflection.build_association(serializer_instance, @instance_options)
294
+ # Assert before instance_eval link meta
295
+ assert_nil association.meta
296
+ assert_nil reflection.options.fetch(:meta)
297
+
298
+ evaluate_association_value(association)
299
+
300
+ link = association.links.fetch(:self)
301
+ assert_respond_to link, :call
302
+ assert_respond_to reflection.options.fetch(:links).fetch(:self), :call
303
+ assert_nil reflection.options.fetch(:meta)
304
+
305
+ # Assert after instance_eval link
306
+ assert_equal 'no_uri_validation', reflection.instance_eval(&link)
307
+ assert_equal @expected_meta, reflection.options.fetch(:meta)
308
+ assert_equal @expected_meta, association.meta
309
+ end
310
+ # rubocop:enable Metrics/AbcSize
311
+
312
+ # rubocop:disable Metrics/AbcSize
313
+ def test_reflection_block_with_meta_block_in_link_block_mutates_the_reflection_meta
314
+ serializer_class = Class.new(ActiveModel::Serializer) do
315
+ has_one :blog do
316
+ link :self do
317
+ meta do
318
+ { id: object.blog.id }
319
+ end
320
+ 'no_uri_validation'
321
+ end
322
+ end
323
+ end
324
+ serializer_instance = serializer_class.new(@model, @instance_options)
325
+
326
+ # Get Reflection
327
+ reflection = serializer_class._reflections.fetch(:blog)
328
+ assert_nil reflection.options.fetch(:meta)
329
+
330
+ # Build Association
331
+ association = reflection.build_association(serializer_instance, @instance_options)
332
+ assert_nil association.meta
333
+ assert_nil reflection.options.fetch(:meta)
334
+
335
+ # Assert before instance_eval link
336
+
337
+ evaluate_association_value(association)
338
+
339
+ link = association.links.fetch(:self)
340
+ assert_nil reflection.options.fetch(:meta)
341
+ assert_respond_to link, :call
342
+ assert_respond_to association.links.fetch(:self), :call
343
+
344
+ # Assert after instance_eval link
345
+ assert_equal 'no_uri_validation', reflection.instance_eval(&link)
346
+ assert_respond_to association.links.fetch(:self), :call
347
+ # Assert before instance_eval link meta
348
+ assert_respond_to reflection.options.fetch(:meta), :call
349
+ assert_respond_to association.meta, :call
350
+
351
+ # Assert after instance_eval link meta
352
+ assert_equal @expected_meta, reflection.instance_eval(&reflection.options.fetch(:meta))
353
+ assert_respond_to association.meta, :call
354
+ end
355
+ # rubocop:enable Metrics/AbcSize
356
+
357
+ def test_no_href_in_vanilla_reflection
358
+ serializer_class = Class.new(ActiveModel::Serializer) do
359
+ has_one :blog do
360
+ link :self do
361
+ href 'no_uri_validation'
362
+ end
363
+ end
364
+ end
365
+ serializer_instance = serializer_class.new(@model, @instance_options)
366
+
367
+ # Get Reflection
368
+ reflection = serializer_class._reflections.fetch(:blog)
369
+ assert_equal @empty_links, reflection.options.fetch(:links)
370
+
371
+ # Build Association
372
+ association = reflection.build_association(serializer_instance, @instance_options)
373
+ # Assert before instance_eval link
374
+
375
+ evaluate_association_value(association)
376
+
377
+ link = association.links.fetch(:self)
378
+ assert_respond_to link, :call
379
+
380
+ # Assert after instance_eval link
381
+ exception = assert_raise(NoMethodError) do
382
+ reflection.instance_eval(&link)
383
+ end
384
+ assert_match(/undefined method `href'/, exception.message)
385
+ end
386
+
387
+ # rubocop:disable Metrics/AbcSize
388
+ def test_mutating_reflection_block_is_not_thread_safe
389
+ serializer_class = Class.new(ActiveModel::Serializer) do
390
+ has_one :blog do
391
+ meta(id: object.blog.id)
392
+ end
393
+ end
394
+ model1_meta = @expected_meta
395
+ # Evaluate reflection meta for model with id 1
396
+ serializer_instance = serializer_class.new(@model, @instance_options)
397
+ reflection = serializer_class._reflections.fetch(:blog)
398
+ assert_nil reflection.options.fetch(:meta)
399
+ association = reflection.build_association(serializer_instance, @instance_options)
400
+
401
+ evaluate_association_value(association)
402
+
403
+ assert_equal model1_meta, association.meta
404
+ assert_equal model1_meta, reflection.options.fetch(:meta)
405
+
406
+ model2_meta = @expected_meta.merge(id: 2)
407
+ # Evaluate reflection meta for model with id 2
408
+ @model.blog.id = 2
409
+ assert_equal 2, @model.blog.id # sanity check
410
+ serializer_instance = serializer_class.new(@model, @instance_options)
411
+ reflection = serializer_class._reflections.fetch(:blog)
412
+
413
+ # WARN: Thread-safety issue
414
+ # Before the reflection is evaluated, it has the value from the previous evaluation
415
+ assert_equal model1_meta, reflection.options.fetch(:meta)
416
+
417
+ association = reflection.build_association(serializer_instance, @instance_options)
418
+
419
+ evaluate_association_value(association)
420
+
421
+ assert_equal model2_meta, association.meta
422
+ assert_equal model2_meta, reflection.options.fetch(:meta)
423
+ end
424
+ # rubocop:enable Metrics/AbcSize
425
+ end
426
+ end
427
+ end
@@ -8,7 +8,7 @@ module ActiveModel
8
8
  end
9
9
 
10
10
  def test_overwrite_root
11
- serializer = VirtualValueSerializer.new(@virtual_value, { root: 'smth' })
11
+ serializer = VirtualValueSerializer.new(@virtual_value, root: 'smth')
12
12
  assert_equal('smth', serializer.json_key)
13
13
  end
14
14
 
@@ -2,10 +2,10 @@ module ActiveModel
2
2
  class Serializer
3
3
  class SerializationTest < ActiveSupport::TestCase
4
4
  class Blog < ActiveModelSerializers::Model
5
- attr_accessor :id, :name, :authors
5
+ attributes :id, :name, :authors
6
6
  end
7
7
  class Author < ActiveModelSerializers::Model
8
- attr_accessor :id, :name
8
+ attributes :id, :name
9
9
  end
10
10
  class BlogSerializer < ActiveModel::Serializer
11
11
  attributes :id
@@ -28,8 +28,8 @@ module ActiveModel
28
28
 
29
29
  class SerializerTest < ActiveSupport::TestCase
30
30
  module ResourceNamespace
31
- Post = Class.new(::Model)
32
- Comment = Class.new(::Model)
31
+ class Post < ::Model; end
32
+ class Comment < ::Model; end
33
33
 
34
34
  class PostSerializer < ActiveModel::Serializer
35
35
  class CommentSerializer < ActiveModel::Serializer
@@ -41,10 +41,12 @@ module ActiveModel
41
41
  end
42
42
 
43
43
  class CustomProfile
44
- def serializer_class; ProfileSerializer; end
44
+ def serializer_class
45
+ ProfileSerializer
46
+ end
45
47
  end
46
48
 
47
- Tweet = Class.new(::Model)
49
+ class Tweet < ::Model; end
48
50
  TweetSerializer = Class.new
49
51
 
50
52
  def setup
@@ -57,7 +59,7 @@ module ActiveModel
57
59
 
58
60
  def test_serializer_for_non_ams_serializer
59
61
  serializer = ActiveModel::Serializer.serializer_for(@tweet)
60
- assert_equal nil, serializer
62
+ assert_nil serializer
61
63
  end
62
64
 
63
65
  def test_serializer_for_existing_serializer
@@ -69,12 +71,12 @@ module ActiveModel
69
71
  serializer = with_serializer_lookup_disabled do
70
72
  ActiveModel::Serializer.serializer_for(@profile)
71
73
  end
72
- assert_equal nil, serializer
74
+ assert_nil serializer
73
75
  end
74
76
 
75
77
  def test_serializer_for_not_existing_serializer
76
78
  serializer = ActiveModel::Serializer.serializer_for(@model)
77
- assert_equal nil, serializer
79
+ assert_nil serializer
78
80
  end
79
81
 
80
82
  def test_serializer_inherited_serializer
@@ -86,7 +88,7 @@ module ActiveModel
86
88
  serializer = with_serializer_lookup_disabled do
87
89
  ActiveModel::Serializer.serializer_for(@my_profile)
88
90
  end
89
- assert_equal nil, serializer
91
+ assert_nil serializer
90
92
  end
91
93
 
92
94
  def test_serializer_custom_serializer
@@ -112,7 +114,7 @@ module ActiveModel
112
114
  serializer = with_serializer_lookup_disabled do
113
115
  ActiveModel::Serializer.serializer_for(post)
114
116
  end
115
- assert_equal nil, serializer
117
+ assert_nil serializer
116
118
  end
117
119
 
118
120
  def test_serializer_for_nested_resource
@@ -126,7 +128,7 @@ module ActiveModel
126
128
  serializer = with_serializer_lookup_disabled do
127
129
  ResourceNamespace::PostSerializer.serializer_for(comment)
128
130
  end
129
- assert_equal nil, serializer
131
+ assert_nil serializer
130
132
  end
131
133
  end
132
134
  end