active_model_serializers 0.10.0 → 0.10.9

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