active_model_serializers 0.10.5 → 0.10.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +4 -1
  3. data/CHANGELOG.md +16 -2
  4. data/README.md +2 -2
  5. data/Rakefile +1 -30
  6. data/active_model_serializers.gemspec +1 -1
  7. data/bin/rubocop +38 -0
  8. data/docs/general/adapters.md +25 -9
  9. data/docs/general/getting_started.md +1 -1
  10. data/docs/general/rendering.md +18 -4
  11. data/docs/general/serializers.md +21 -2
  12. data/docs/howto/add_pagination_links.md +1 -1
  13. data/docs/integrations/ember-and-json-api.md +3 -0
  14. data/lib/active_model/serializer.rb +252 -74
  15. data/lib/active_model/serializer/association.rb +51 -14
  16. data/lib/active_model/serializer/belongs_to_reflection.rb +5 -1
  17. data/lib/active_model/serializer/concerns/caching.rb +29 -21
  18. data/lib/active_model/serializer/has_many_reflection.rb +4 -1
  19. data/lib/active_model/serializer/has_one_reflection.rb +1 -1
  20. data/lib/active_model/serializer/lazy_association.rb +95 -0
  21. data/lib/active_model/serializer/reflection.rb +119 -75
  22. data/lib/active_model/serializer/version.rb +1 -1
  23. data/lib/active_model_serializers/adapter/json_api.rb +30 -17
  24. data/lib/active_model_serializers/adapter/json_api/relationship.rb +38 -9
  25. data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +9 -0
  26. data/lib/active_model_serializers/model.rb +5 -4
  27. data/lib/tasks/rubocop.rake +53 -0
  28. data/test/action_controller/adapter_selector_test.rb +2 -2
  29. data/test/serializers/associations_test.rb +64 -31
  30. data/test/serializers/reflection_test.rb +427 -0
  31. metadata +9 -12
  32. data/lib/active_model/serializer/collection_reflection.rb +0 -7
  33. data/lib/active_model/serializer/concerns/associations.rb +0 -102
  34. data/lib/active_model/serializer/concerns/attributes.rb +0 -82
  35. data/lib/active_model/serializer/concerns/configuration.rb +0 -59
  36. data/lib/active_model/serializer/concerns/links.rb +0 -35
  37. data/lib/active_model/serializer/concerns/meta.rb +0 -29
  38. data/lib/active_model/serializer/concerns/type.rb +0 -25
  39. data/lib/active_model/serializer/singular_reflection.rb +0 -7
@@ -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
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active_model_serializers
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.5
4
+ version: 0.10.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Steve Klabnik
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-03-07 00:00:00.000000000 Z
11
+ date: 2017-05-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -209,7 +209,7 @@ dependencies:
209
209
  version: '0.13'
210
210
  - - "<"
211
211
  - !ruby/object:Gem::Version
212
- version: '1.0'
212
+ version: 0.19.1
213
213
  type: :development
214
214
  prerelease: false
215
215
  version_requirements: !ruby/object:Gem::Requirement
@@ -219,7 +219,7 @@ dependencies:
219
219
  version: '0.13'
220
220
  - - "<"
221
221
  - !ruby/object:Gem::Version
222
- version: '1.0'
222
+ version: 0.19.1
223
223
  - !ruby/object:Gem::Dependency
224
224
  name: json_schema
225
225
  requirement: !ruby/object:Gem::Requirement
@@ -279,6 +279,7 @@ files:
279
279
  - appveyor.yml
280
280
  - bin/bench
281
281
  - bin/bench_regression
282
+ - bin/rubocop
282
283
  - bin/serve_benchmark
283
284
  - docs/README.md
284
285
  - docs/STYLE.md
@@ -323,25 +324,18 @@ files:
323
324
  - lib/active_model/serializer/association.rb
324
325
  - lib/active_model/serializer/attribute.rb
325
326
  - lib/active_model/serializer/belongs_to_reflection.rb
326
- - lib/active_model/serializer/collection_reflection.rb
327
327
  - lib/active_model/serializer/collection_serializer.rb
328
- - lib/active_model/serializer/concerns/associations.rb
329
- - lib/active_model/serializer/concerns/attributes.rb
330
328
  - lib/active_model/serializer/concerns/caching.rb
331
- - lib/active_model/serializer/concerns/configuration.rb
332
- - lib/active_model/serializer/concerns/links.rb
333
- - lib/active_model/serializer/concerns/meta.rb
334
- - lib/active_model/serializer/concerns/type.rb
335
329
  - lib/active_model/serializer/error_serializer.rb
336
330
  - lib/active_model/serializer/errors_serializer.rb
337
331
  - lib/active_model/serializer/field.rb
338
332
  - lib/active_model/serializer/fieldset.rb
339
333
  - lib/active_model/serializer/has_many_reflection.rb
340
334
  - lib/active_model/serializer/has_one_reflection.rb
335
+ - lib/active_model/serializer/lazy_association.rb
341
336
  - lib/active_model/serializer/lint.rb
342
337
  - lib/active_model/serializer/null.rb
343
338
  - lib/active_model/serializer/reflection.rb
344
- - lib/active_model/serializer/singular_reflection.rb
345
339
  - lib/active_model/serializer/version.rb
346
340
  - lib/active_model_serializers.rb
347
341
  - lib/active_model_serializers/adapter.rb
@@ -379,6 +373,7 @@ files:
379
373
  - lib/grape/active_model_serializers.rb
380
374
  - lib/grape/formatters/active_model_serializers.rb
381
375
  - lib/grape/helpers/active_model_serializers.rb
376
+ - lib/tasks/rubocop.rake
382
377
  - test/action_controller/adapter_selector_test.rb
383
378
  - test/action_controller/explicit_serializer_test.rb
384
379
  - test/action_controller/json/include_test.rb
@@ -464,6 +459,7 @@ files:
464
459
  - test/serializers/meta_test.rb
465
460
  - test/serializers/options_test.rb
466
461
  - test/serializers/read_attribute_for_serialization_test.rb
462
+ - test/serializers/reflection_test.rb
467
463
  - test/serializers/root_test.rb
468
464
  - test/serializers/serialization_test.rb
469
465
  - test/serializers/serializer_for_test.rb
@@ -590,6 +586,7 @@ test_files:
590
586
  - test/serializers/meta_test.rb
591
587
  - test/serializers/options_test.rb
592
588
  - test/serializers/read_attribute_for_serialization_test.rb
589
+ - test/serializers/reflection_test.rb
593
590
  - test/serializers/root_test.rb
594
591
  - test/serializers/serialization_test.rb
595
592
  - test/serializers/serializer_for_test.rb