active_model_serializers 0.10.0 → 0.10.2

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 (109) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -4
  3. data/.travis.yml +1 -0
  4. data/CHANGELOG.md +39 -2
  5. data/Gemfile +1 -1
  6. data/README.md +21 -24
  7. data/Rakefile +3 -3
  8. data/active_model_serializers.gemspec +19 -23
  9. data/docs/general/adapters.md +4 -2
  10. data/docs/general/configuration_options.md +6 -1
  11. data/docs/general/deserialization.md +1 -1
  12. data/docs/general/fields.md +31 -0
  13. data/docs/general/rendering.md +7 -2
  14. data/docs/general/serializers.md +62 -3
  15. data/docs/howto/add_pagination_links.md +2 -3
  16. data/docs/integrations/ember-and-json-api.md +25 -10
  17. data/docs/jsonapi/schema.md +1 -1
  18. data/lib/action_controller/serialization.rb +4 -3
  19. data/lib/active_model/serializer/adapter/base.rb +2 -0
  20. data/lib/active_model/serializer/array_serializer.rb +8 -5
  21. data/lib/active_model/serializer/associations.rb +6 -7
  22. data/lib/active_model/serializer/belongs_to_reflection.rb +0 -3
  23. data/lib/active_model/serializer/caching.rb +67 -112
  24. data/lib/active_model/serializer/collection_serializer.rb +30 -10
  25. data/lib/active_model/serializer/configuration.rb +1 -0
  26. data/lib/active_model/serializer/error_serializer.rb +11 -7
  27. data/lib/active_model/serializer/errors_serializer.rb +25 -20
  28. data/lib/active_model/serializer/has_many_reflection.rb +0 -3
  29. data/lib/active_model/serializer/has_one_reflection.rb +0 -3
  30. data/lib/active_model/serializer/lint.rb +134 -130
  31. data/lib/active_model/serializer/reflection.rb +3 -3
  32. data/lib/active_model/serializer/version.rb +1 -1
  33. data/lib/active_model/serializer.rb +57 -15
  34. data/lib/active_model_serializers/adapter/attributes.rb +2 -67
  35. data/lib/active_model_serializers/adapter/base.rb +38 -38
  36. data/lib/active_model_serializers/adapter/json_api/link.rb +1 -1
  37. data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +8 -1
  38. data/lib/active_model_serializers/adapter/json_api.rb +36 -28
  39. data/lib/active_model_serializers/adapter.rb +6 -0
  40. data/lib/active_model_serializers/deprecate.rb +1 -2
  41. data/lib/active_model_serializers/deserialization.rb +2 -0
  42. data/lib/active_model_serializers/model.rb +3 -1
  43. data/lib/active_model_serializers/railtie.rb +3 -1
  44. data/lib/active_model_serializers/register_jsonapi_renderer.rb +44 -31
  45. data/lib/active_model_serializers/serialization_context.rb +10 -3
  46. data/lib/active_model_serializers.rb +6 -0
  47. data/lib/generators/rails/serializer_generator.rb +3 -3
  48. data/lib/grape/active_model_serializers.rb +7 -5
  49. data/lib/grape/formatters/active_model_serializers.rb +19 -2
  50. data/lib/grape/helpers/active_model_serializers.rb +1 -0
  51. data/test/action_controller/adapter_selector_test.rb +4 -4
  52. data/test/action_controller/explicit_serializer_test.rb +5 -4
  53. data/test/action_controller/json/include_test.rb +106 -27
  54. data/test/action_controller/json_api/errors_test.rb +6 -7
  55. data/test/action_controller/json_api/linked_test.rb +29 -24
  56. data/test/action_controller/json_api/pagination_test.rb +19 -19
  57. data/test/action_controller/serialization_test.rb +10 -7
  58. data/test/active_model_serializers/json_pointer_test.rb +15 -13
  59. data/test/active_model_serializers/key_transform_test.rb +254 -252
  60. data/test/active_model_serializers/model_test.rb +6 -4
  61. data/test/active_model_serializers/register_jsonapi_renderer_test_isolated.rb +143 -0
  62. data/test/active_model_serializers/serialization_context_test_isolated.rb +23 -10
  63. data/test/adapter/json/collection_test.rb +14 -0
  64. data/test/adapter/json/transform_test.rb +14 -14
  65. data/test/adapter/json_api/collection_test.rb +4 -3
  66. data/test/adapter/json_api/errors_test.rb +17 -19
  67. data/test/adapter/json_api/has_many_test.rb +18 -18
  68. data/test/adapter/json_api/json_api_test.rb +5 -7
  69. data/test/adapter/json_api/linked_test.rb +9 -6
  70. data/test/adapter/json_api/links_test.rb +3 -1
  71. data/test/adapter/json_api/pagination_links_test.rb +19 -7
  72. data/test/adapter/json_api/relationships_test.rb +9 -4
  73. data/test/adapter/json_api/resource_identifier_test.rb +7 -2
  74. data/test/adapter/json_api/resource_meta_test.rb +3 -3
  75. data/test/adapter/json_api/transform_test.rb +251 -250
  76. data/test/adapter/json_api/type_test.rb +1 -1
  77. data/test/adapter/json_test.rb +8 -7
  78. data/test/adapter/null_test.rb +1 -2
  79. data/test/adapter/polymorphic_test.rb +5 -5
  80. data/test/adapter_test.rb +1 -1
  81. data/test/benchmark/app.rb +1 -1
  82. data/test/benchmark/bm_caching.rb +15 -15
  83. data/test/benchmark/bm_transform.rb +16 -5
  84. data/test/benchmark/controllers.rb +16 -17
  85. data/test/benchmark/fixtures.rb +72 -72
  86. data/test/cache_test.rb +101 -45
  87. data/test/collection_serializer_test.rb +2 -2
  88. data/test/fixtures/poro.rb +8 -7
  89. data/test/grape_test.rb +152 -56
  90. data/test/lint_test.rb +1 -1
  91. data/test/logger_test.rb +13 -11
  92. data/test/serializable_resource_test.rb +18 -22
  93. data/test/serializers/associations_test.rb +10 -10
  94. data/test/serializers/attribute_test.rb +1 -1
  95. data/test/serializers/attributes_test.rb +1 -1
  96. data/test/serializers/fieldset_test.rb +1 -1
  97. data/test/serializers/meta_test.rb +12 -6
  98. data/test/serializers/root_test.rb +1 -1
  99. data/test/serializers/serializer_for_test.rb +3 -1
  100. data/test/support/isolated_unit.rb +5 -2
  101. data/test/support/rails5_shims.rb +8 -2
  102. data/test/support/rails_app.rb +0 -9
  103. data/test/support/serialization_testing.rb +7 -5
  104. metadata +54 -24
  105. data/.rubocop_todo.yml +0 -167
  106. data/lib/active_model/serializer/include_tree.rb +0 -111
  107. data/test/include_tree/from_include_args_test.rb +0 -26
  108. data/test/include_tree/from_string_test.rb +0 -94
  109. data/test/include_tree/include_args_to_hash_test.rb +0 -64
data/test/cache_test.rb CHANGED
@@ -101,14 +101,14 @@ module ActiveModelSerializers
101
101
  uncached_author_serializer = AuthorSerializer.new(uncached_author)
102
102
 
103
103
  render_object_with_cache(uncached_author)
104
- key = "#{uncached_author_serializer.class._cache_key}/#{uncached_author_serializer.object.id}-#{uncached_author_serializer.object.updated_at.strftime("%Y%m%d%H%M%S%9N")}"
105
- key = "#{key}/#{adapter.cached_name}"
104
+ key = "#{uncached_author_serializer.class._cache_key}/#{uncached_author_serializer.object.id}-#{uncached_author_serializer.object.updated_at.strftime('%Y%m%d%H%M%S%9N')}"
105
+ key = "#{key}/#{adapter.cache_key}"
106
106
  assert_equal(uncached_author_serializer.attributes.to_json, cache_store.fetch(key).to_json)
107
107
  end
108
108
 
109
109
  def test_default_cache_key_fallback
110
110
  render_object_with_cache(@comment)
111
- key = "#{@comment.cache_key}/#{adapter.cached_name}"
111
+ key = "#{@comment.cache_key}/#{adapter.cache_key}"
112
112
  assert_equal(@comment_serializer.attributes.to_json, cache_store.fetch(key).to_json)
113
113
  end
114
114
 
@@ -117,7 +117,7 @@ module ActiveModelSerializers
117
117
  e = assert_raises ActiveModel::Serializer::UndefinedCacheKey do
118
118
  render_object_with_cache(article)
119
119
  end
120
- assert_match(/ActiveModelSerializers::CacheTest::Article must define #cache_key, or the 'key:' option must be passed into 'CachedActiveModelSerializers_CacheTest_ArticleSerializer.cache'/, e.message)
120
+ assert_match(/ActiveModelSerializers::CacheTest::Article must define #cache_key, or the 'key:' option must be passed into 'ActiveModelSerializers::CacheTest::ArticleSerializer.cache'/, e.message)
121
121
  end
122
122
 
123
123
  def test_cache_options_definition
@@ -127,7 +127,7 @@ module ActiveModelSerializers
127
127
  end
128
128
 
129
129
  def test_fragment_cache_definition
130
- assert_equal([:name], @role_serializer.class._cache_only)
130
+ assert_equal([:name, :slug], @role_serializer.class._cache_only)
131
131
  assert_equal([:content], @bio_serializer.class._cache_except)
132
132
  end
133
133
 
@@ -139,9 +139,9 @@ module ActiveModelSerializers
139
139
  Timecop.freeze(Time.current) do
140
140
  render_object_with_cache(@post)
141
141
 
142
- key = "#{@post.cache_key}/#{adapter.cached_name}"
142
+ key = "#{@post.cache_key}/#{adapter.cache_key}"
143
143
  assert_equal(@post_serializer.attributes, cache_store.fetch(key))
144
- key = "#{@comment.cache_key}/#{adapter.cached_name}"
144
+ key = "#{@comment.cache_key}/#{adapter.cache_key}"
145
145
  assert_equal(@comment_serializer.attributes, cache_store.fetch(key))
146
146
  end
147
147
  end
@@ -152,9 +152,9 @@ module ActiveModelSerializers
152
152
  render_object_with_cache(@post)
153
153
 
154
154
  # Check if it cached the objects separately
155
- key = "#{@post.cache_key}/#{adapter.cached_name}"
155
+ key = "#{@post.cache_key}/#{adapter.cache_key}"
156
156
  assert_equal(@post_serializer.attributes, cache_store.fetch(key))
157
- key = "#{@comment.cache_key}/#{adapter.cached_name}"
157
+ key = "#{@comment.cache_key}/#{adapter.cache_key}"
158
158
  assert_equal(@comment_serializer.attributes, cache_store.fetch(key))
159
159
 
160
160
  # Simulating update on comments relationship with Post
@@ -166,9 +166,9 @@ module ActiveModelSerializers
166
166
  render_object_with_cache(@post)
167
167
 
168
168
  # Check if the the new comment was cached
169
- key = "#{new_comment.cache_key}/#{adapter.cached_name}"
169
+ key = "#{new_comment.cache_key}/#{adapter.cache_key}"
170
170
  assert_equal(new_comment_serializer.attributes, cache_store.fetch(key))
171
- key = "#{@post.cache_key}/#{adapter.cached_name}"
171
+ key = "#{@post.cache_key}/#{adapter.cache_key}"
172
172
  assert_equal(@post_serializer.attributes, cache_store.fetch(key))
173
173
  end
174
174
  end
@@ -178,14 +178,14 @@ module ActiveModelSerializers
178
178
  id: @location.id,
179
179
  lat: @location.lat,
180
180
  lng: @location.lng,
181
- place: 'Nowhere'
181
+ address: 'Nowhere'
182
182
  }
183
183
 
184
184
  hash = render_object_with_cache(@location)
185
185
 
186
186
  assert_equal(hash, expected_result)
187
- key = "#{@location.cache_key}/#{adapter.cached_name}"
188
- assert_equal({ place: 'Nowhere' }, cache_store.fetch(key))
187
+ key = "#{@location.cache_key}/#{adapter.cache_key}"
188
+ assert_equal({ address: 'Nowhere' }, cache_store.fetch(key))
189
189
  end
190
190
 
191
191
  def test_fragment_cache_with_inheritance
@@ -204,7 +204,7 @@ module ActiveModelSerializers
204
204
 
205
205
  # Based on original failing test by @kevintyll
206
206
  # rubocop:disable Metrics/AbcSize
207
- def test_a_serializer_rendered_by_two_adapter_returns_differently_cached_attributes
207
+ def test_a_serializer_rendered_by_two_adapter_returns_differently_fetch_attributes
208
208
  Object.const_set(:Alert, Class.new(ActiveModelSerializers::Model) do
209
209
  attr_accessor :id, :status, :resource, :started_at, :ended_at, :updated_at, :created_at
210
210
  end)
@@ -225,7 +225,7 @@ module ActiveModelSerializers
225
225
  created_at: Time.new(2016, 3, 31, 21, 37, 35, 0)
226
226
  )
227
227
 
228
- expected_cached_attributes = {
228
+ expected_fetch_attributes = {
229
229
  id: 1,
230
230
  status: 'fail',
231
231
  resource: 'resource-1',
@@ -250,7 +250,7 @@ module ActiveModelSerializers
250
250
  # Assert attributes are serialized correctly
251
251
  serializable_alert = serializable(alert, serializer: AlertSerializer, adapter: :attributes)
252
252
  attributes_serialization = serializable_alert.as_json
253
- assert_equal expected_cached_attributes, alert.attributes
253
+ assert_equal expected_fetch_attributes, alert.attributes
254
254
  assert_equal alert.attributes, attributes_serialization
255
255
  attributes_cache_key = serializable_alert.adapter.serializer.cache_key(serializable_alert.adapter)
256
256
  assert_equal attributes_serialization, cache_store.fetch(attributes_cache_key)
@@ -276,7 +276,7 @@ module ActiveModelSerializers
276
276
 
277
277
  def test_uses_file_digest_in_cache_key
278
278
  render_object_with_cache(@blog)
279
- key = "#{@blog.cache_key}/#{adapter.cached_name}/#{::Model::FILE_DIGEST}"
279
+ key = "#{@blog.cache_key}/#{adapter.cache_key}/#{::Model::FILE_DIGEST}"
280
280
  assert_equal(@blog_serializer.attributes, cache_store.fetch(key))
281
281
  end
282
282
 
@@ -286,33 +286,66 @@ module ActiveModelSerializers
286
286
 
287
287
  def test_object_cache_keys
288
288
  serializable = ActiveModelSerializers::SerializableResource.new([@comment, @comment])
289
- include_tree = ActiveModel::Serializer::IncludeTree.from_include_args('*')
289
+ include_directive = JSONAPI::IncludeDirective.new('*', allow_wildcard: true)
290
290
 
291
- actual = ActiveModel::Serializer.object_cache_keys(serializable.adapter.serializer, serializable.adapter, include_tree)
291
+ actual = ActiveModel::Serializer.object_cache_keys(serializable.adapter.serializer, serializable.adapter, include_directive)
292
292
 
293
293
  assert_equal 3, actual.size
294
- assert actual.any? { |key| key == "comment/1/#{serializable.adapter.cached_name}" }
294
+ assert actual.any? { |key| key == "comment/1/#{serializable.adapter.cache_key}" }
295
295
  assert actual.any? { |key| key =~ %r{post/post-\d+} }
296
296
  assert actual.any? { |key| key =~ %r{author/author-\d+} }
297
297
  end
298
298
 
299
- def test_cached_attributes
300
- serializer = ActiveModel::Serializer::CollectionSerializer.new([@comment, @comment])
299
+ def test_fetch_attributes_from_cache
300
+ serializers = ActiveModel::Serializer::CollectionSerializer.new([@comment, @comment])
301
301
 
302
302
  Timecop.freeze(Time.current) do
303
303
  render_object_with_cache(@comment)
304
304
 
305
- attributes = Adapter::Attributes.new(serializer)
306
- attributes.send(:cache_attributes)
307
- cached_attributes = attributes.instance_variable_get(:@cached_attributes)
305
+ options = {}
306
+ adapter_options = {}
307
+ adapter_instance = ActiveModelSerializers::Adapter::Attributes.new(serializers, adapter_options)
308
+ serializers.serializable_hash(adapter_options, options, adapter_instance)
309
+ cached_attributes = adapter_options.fetch(:cached_attributes)
308
310
 
309
- assert_equal cached_attributes["#{@comment.cache_key}/#{attributes.cached_name}"], Comment.new(id: 1, body: 'ZOMG A COMMENT').attributes
310
- assert_equal cached_attributes["#{@comment.post.cache_key}/#{attributes.cached_name}"], Post.new(id: 'post', title: 'New Post', body: 'Body').attributes
311
+ include_directive = ActiveModelSerializers.default_include_directive
312
+ manual_cached_attributes = ActiveModel::Serializer.cache_read_multi(serializers, adapter_instance, include_directive)
313
+ assert_equal manual_cached_attributes, cached_attributes
314
+
315
+ assert_equal cached_attributes["#{@comment.cache_key}/#{adapter_instance.cache_key}"], Comment.new(id: 1, body: 'ZOMG A COMMENT').attributes
316
+ assert_equal cached_attributes["#{@comment.post.cache_key}/#{adapter_instance.cache_key}"], Post.new(id: 'post', title: 'New Post', body: 'Body').attributes
311
317
 
312
318
  writer = @comment.post.blog.writer
313
319
  writer_cache_key = writer.cache_key
320
+ assert_equal cached_attributes["#{writer_cache_key}/#{adapter_instance.cache_key}"], Author.new(id: 'author', name: 'Joao M. D. Moura').attributes
321
+ end
322
+ end
323
+
324
+ def test_cache_read_multi_with_fragment_cache_enabled
325
+ post_serializer = Class.new(ActiveModel::Serializer) do
326
+ cache except: [:body]
327
+ end
314
328
 
315
- assert_equal cached_attributes["#{writer_cache_key}/#{attributes.cached_name}"], Author.new(id: 'author', name: 'Joao M. D. Moura').attributes
329
+ serializers = ActiveModel::Serializer::CollectionSerializer.new([@post, @post], serializer: post_serializer)
330
+
331
+ Timecop.freeze(Time.current) do
332
+ # Warming up.
333
+ options = {}
334
+ adapter_options = {}
335
+ adapter_instance = ActiveModelSerializers::Adapter::Attributes.new(serializers, adapter_options)
336
+ serializers.serializable_hash(adapter_options, options, adapter_instance)
337
+
338
+ # Should find something with read_multi now
339
+ adapter_options = {}
340
+ serializers.serializable_hash(adapter_options, options, adapter_instance)
341
+ cached_attributes = adapter_options.fetch(:cached_attributes)
342
+
343
+ include_directive = ActiveModelSerializers.default_include_directive
344
+ manual_cached_attributes = ActiveModel::Serializer.cache_read_multi(serializers, adapter_instance, include_directive)
345
+
346
+ refute_equal 0, cached_attributes.size
347
+ refute_equal 0, manual_cached_attributes.size
348
+ assert_equal manual_cached_attributes, cached_attributes
316
349
  end
317
350
  end
318
351
 
@@ -429,25 +462,53 @@ module ActiveModelSerializers
429
462
  end
430
463
 
431
464
  def test_fragment_fetch_with_virtual_attributes
432
- @author = Author.new(name: 'Joao M. D. Moura')
433
- @role = Role.new(name: 'Great Author', description: nil)
434
- @role.author = [@author]
435
- @role_serializer = RoleSerializer.new(@role)
436
- @role_hash = @role_serializer.fetch_fragment_cache(ActiveModelSerializers::Adapter.configured_adapter.new(@role_serializer))
465
+ author = Author.new(name: 'Joao M. D. Moura')
466
+ role = Role.new(name: 'Great Author', description: nil)
467
+ role.author = [author]
468
+ role_serializer = RoleSerializer.new(role)
469
+ adapter_instance = ActiveModelSerializers::Adapter.configured_adapter.new(role_serializer)
470
+ expected_result = {
471
+ id: role.id,
472
+ description: role.description,
473
+ slug: "#{role.name}-#{role.id}",
474
+ name: role.name
475
+ }
476
+ cache_store.clear
437
477
 
478
+ role_hash = role_serializer.fetch_attributes_fragment(adapter_instance)
479
+ assert_equal(role_hash, expected_result)
480
+
481
+ role.attributes[:id] = 'this has been updated'
482
+ role.name = 'this was cached'
483
+
484
+ role_hash = role_serializer.fetch_attributes_fragment(adapter_instance)
485
+ assert_equal(expected_result.merge(id: role.id), role_hash)
486
+ end
487
+
488
+ def test_fragment_fetch_with_except
489
+ adapter_instance = ActiveModelSerializers::Adapter.configured_adapter.new(@bio_serializer)
438
490
  expected_result = {
439
- id: @role.id,
440
- description: @role.description,
441
- slug: "#{@role.name}-#{@role.id}",
442
- name: @role.name
491
+ id: @bio.id,
492
+ rating: nil,
493
+ content: @bio.content
443
494
  }
444
- assert_equal(@role_hash, expected_result)
495
+ cache_store.clear
496
+
497
+ bio_hash = @bio_serializer.fetch_attributes_fragment(adapter_instance)
498
+ assert_equal(expected_result, bio_hash)
499
+
500
+ @bio.content = 'this has been updated'
501
+ @bio.rating = 'this was cached'
502
+
503
+ bio_hash = @bio_serializer.fetch_attributes_fragment(adapter_instance)
504
+ assert_equal(expected_result.merge(content: @bio.content), bio_hash)
445
505
  end
446
506
 
447
507
  def test_fragment_fetch_with_namespaced_object
448
508
  @spam = Spam::UnrelatedLink.new(id: 'spam-id-1')
449
509
  @spam_serializer = Spam::UnrelatedLinkSerializer.new(@spam)
450
- @spam_hash = @spam_serializer.fetch_fragment_cache(ActiveModelSerializers::Adapter.configured_adapter.new(@spam_serializer))
510
+ adapter_instance = ActiveModelSerializers::Adapter.configured_adapter.new(@spam_serializer)
511
+ @spam_hash = @spam_serializer.fetch_attributes_fragment(adapter_instance)
451
512
  expected_result = {
452
513
  id: @spam.id
453
514
  }
@@ -476,10 +537,5 @@ module ActiveModelSerializers
476
537
  def adapter
477
538
  @serializable_resource.adapter
478
539
  end
479
-
480
- def cached_serialization(serializer)
481
- cache_key = serializer.cache_key(adapter)
482
- cache_store.fetch(cache_key)
483
- end
484
540
  end
485
541
  end
@@ -11,7 +11,7 @@ module ActiveModel
11
11
  @comment = Comment.new
12
12
  @post = Post.new
13
13
  @resource = build_named_collection @comment, @post
14
- @serializer = collection_serializer.new(@resource, { some: :options })
14
+ @serializer = collection_serializer.new(@resource, some: :options)
15
15
  end
16
16
 
17
17
  def collection_serializer
@@ -44,7 +44,7 @@ module ActiveModel
44
44
  end
45
45
 
46
46
  def test_serializer_option_not_passed_to_each_serializer
47
- serializers = collection_serializer.new([@post], { serializer: PostSerializer }).to_a
47
+ serializers = collection_serializer.new([@post], serializer: PostSerializer).to_a
48
48
 
49
49
  refute serializers.first.custom_options.key?(:serializer)
50
50
  end
@@ -8,7 +8,7 @@ class Model < ActiveModelSerializers::Model
8
8
  # Convenience when not adding @attributes readers and writers
9
9
  def method_missing(meth, *args)
10
10
  if meth.to_s =~ /^(.*)=$/
11
- attributes[$1.to_sym] = args[0]
11
+ attributes[Regexp.last_match(1).to_sym] = args[0]
12
12
  elsif attributes.key?(meth)
13
13
  attributes[meth]
14
14
  else
@@ -64,7 +64,7 @@ VirtualValue = Class.new(Model)
64
64
  Comment = Class.new(Model) do
65
65
  # Uses a custom non-time-based cache key
66
66
  def cache_key
67
- "#{self.class.name.downcase}/#{self.id}"
67
+ "#{self.class.name.downcase}/#{id}"
68
68
  end
69
69
  end
70
70
 
@@ -136,10 +136,11 @@ AuthorSerializer = Class.new(ActiveModel::Serializer) do
136
136
  end
137
137
 
138
138
  RoleSerializer = Class.new(ActiveModel::Serializer) do
139
- cache only: [:name], skip_digest: true
140
- attributes :id, :name, :description, :slug
139
+ cache only: [:name, :slug], skip_digest: true
140
+ attributes :id, :name, :description
141
+ attribute :friendly_id, key: :slug
141
142
 
142
- def slug
143
+ def friendly_id
143
144
  "#{object.name}-#{object.id}"
144
145
  end
145
146
 
@@ -153,10 +154,10 @@ LikeSerializer = Class.new(ActiveModel::Serializer) do
153
154
  end
154
155
 
155
156
  LocationSerializer = Class.new(ActiveModel::Serializer) do
156
- cache only: [:place], skip_digest: true
157
+ cache only: [:address], skip_digest: true
157
158
  attributes :id, :lat, :lng
158
159
 
159
- belongs_to :place
160
+ belongs_to :place, key: :address
160
161
 
161
162
  def place
162
163
  'Nowhere'
data/test/grape_test.rb CHANGED
@@ -1,82 +1,178 @@
1
1
  require 'test_helper'
2
2
  require 'grape'
3
3
  require 'grape/active_model_serializers'
4
+ require 'kaminari'
5
+ require 'kaminari/hooks'
6
+ ::Kaminari::Hooks.init
7
+
8
+ module ActiveModelSerializers
9
+ class GrapeTest < ActiveSupport::TestCase
10
+ include Rack::Test::Methods
11
+ module Models
12
+ def self.model1
13
+ ARModels::Post.new(id: 1, title: 'Dummy Title', body: 'Lorem Ipsum')
14
+ end
4
15
 
5
- class ActiveModelSerializers::GrapeTest < ActiveSupport::TestCase
6
- include Rack::Test::Methods
7
- module Models
8
- def self.model1
9
- ARModels::Post.new(id: 1, title: 'Dummy Title', body: 'Lorem Ipsum')
10
- end
16
+ def self.model2
17
+ ARModels::Post.new(id: 2, title: 'Second Dummy Title', body: 'Second Lorem Ipsum')
18
+ end
19
+
20
+ def self.all
21
+ @all ||=
22
+ begin
23
+ model1.save!
24
+ model2.save!
25
+ ARModels::Post.all
26
+ end
27
+ end
28
+
29
+ def self.reset_all
30
+ ARModels::Post.delete_all
31
+ @all = nil
32
+ end
33
+
34
+ def self.collection_per
35
+ 2
36
+ end
11
37
 
12
- def self.model2
13
- ARModels::Post.new(id: 2, title: 'Second Dummy Title', body: 'Second Lorem Ipsum')
38
+ def self.collection
39
+ @collection ||=
40
+ begin
41
+ Kaminari.paginate_array(
42
+ [
43
+ Profile.new(id: 1, name: 'Name 1', description: 'Description 1', comments: 'Comments 1'),
44
+ Profile.new(id: 2, name: 'Name 2', description: 'Description 2', comments: 'Comments 2'),
45
+ Profile.new(id: 3, name: 'Name 3', description: 'Description 3', comments: 'Comments 3'),
46
+ Profile.new(id: 4, name: 'Name 4', description: 'Description 4', comments: 'Comments 4'),
47
+ Profile.new(id: 5, name: 'Name 5', description: 'Description 5', comments: 'Comments 5')
48
+ ]
49
+ ).page(1).per(collection_per)
50
+ end
51
+ end
14
52
  end
15
53
 
16
- def self.all
17
- @all ||=
18
- begin
19
- model1.save!
20
- model2.save!
21
- ARModels::Post.all
54
+ class GrapeTest < Grape::API
55
+ format :json
56
+ include Grape::ActiveModelSerializers
57
+
58
+ resources :grape do
59
+ get '/render' do
60
+ render Models.model1
22
61
  end
23
- end
24
- end
25
62
 
26
- class GrapeTest < Grape::API
27
- format :json
28
- include Grape::ActiveModelSerializers
63
+ get '/render_with_json_api' do
64
+ post = Models.model1
65
+ render post, meta: { page: 1, total_pages: 2 }, adapter: :json_api
66
+ end
29
67
 
30
- resources :grape do
31
- get '/render' do
32
- render Models.model1
33
- end
68
+ get '/render_array_with_json_api' do
69
+ posts = Models.all
70
+ render posts, adapter: :json_api
71
+ end
34
72
 
35
- get '/render_with_json_api' do
36
- post = Models.model1
37
- render post, meta: { page: 1, total_pages: 2 }, adapter: :json_api
38
- end
73
+ get '/render_collection_with_json_api' do
74
+ posts = Models.collection
75
+ render posts, adapter: :json_api
76
+ end
39
77
 
40
- get '/render_array_with_json_api' do
41
- posts = Models.all
42
- render posts, adapter: :json_api
78
+ get '/render_with_implicit_formatter' do
79
+ Models.model1
80
+ end
81
+
82
+ get '/render_array_with_implicit_formatter' do
83
+ Models.all
84
+ end
85
+
86
+ get '/render_collection_with_implicit_formatter' do
87
+ Models.collection
88
+ end
43
89
  end
44
90
  end
45
- end
46
91
 
47
- def app
48
- GrapeTest.new
49
- end
92
+ def app
93
+ Grape::Middleware::Globals.new(GrapeTest.new)
94
+ end
50
95
 
51
- def test_formatter_returns_json
52
- get '/grape/render'
96
+ def test_formatter_returns_json
97
+ get '/grape/render'
53
98
 
54
- post = Models.model1
55
- serializable_resource = serializable(post)
99
+ post = Models.model1
100
+ serializable_resource = serializable(post)
56
101
 
57
- assert last_response.ok?
58
- assert_equal serializable_resource.to_json, last_response.body
59
- end
102
+ assert last_response.ok?
103
+ assert_equal serializable_resource.to_json, last_response.body
104
+ end
60
105
 
61
- def test_render_helper_passes_through_options_correctly
62
- get '/grape/render_with_json_api'
106
+ def test_render_helper_passes_through_options_correctly
107
+ get '/grape/render_with_json_api'
63
108
 
64
- post = Models.model1
65
- serializable_resource = serializable(post, serializer: ARModels::PostSerializer, adapter: :json_api, meta: { page: 1, total_pages: 2 })
109
+ post = Models.model1
110
+ serializable_resource = serializable(post, serializer: ARModels::PostSerializer, adapter: :json_api, meta: { page: 1, total_pages: 2 })
66
111
 
67
- assert last_response.ok?
68
- assert_equal serializable_resource.to_json, last_response.body
69
- end
112
+ assert last_response.ok?
113
+ assert_equal serializable_resource.to_json, last_response.body
114
+ end
115
+
116
+ def test_formatter_handles_arrays
117
+ get '/grape/render_array_with_json_api'
118
+
119
+ posts = Models.all
120
+ serializable_resource = serializable(posts, adapter: :json_api)
121
+
122
+ assert last_response.ok?
123
+ assert_equal serializable_resource.to_json, last_response.body
124
+ ensure
125
+ Models.reset_all
126
+ end
127
+
128
+ def test_formatter_handles_collections
129
+ get '/grape/render_collection_with_json_api'
130
+ assert last_response.ok?
131
+
132
+ representation = JSON.parse(last_response.body)
133
+ assert representation.include?('data')
134
+ assert representation['data'].count == Models.collection_per
135
+ assert representation.include?('links')
136
+ assert representation['links'].count > 0
137
+ end
138
+
139
+ def test_implicit_formatter
140
+ post = Models.model1
141
+ serializable_resource = serializable(post, adapter: :json_api)
142
+
143
+ with_adapter :json_api do
144
+ get '/grape/render_with_implicit_formatter'
145
+ end
146
+
147
+ assert last_response.ok?
148
+ assert_equal serializable_resource.to_json, last_response.body
149
+ end
70
150
 
71
- def test_formatter_handles_arrays
72
- get '/grape/render_array_with_json_api'
151
+ def test_implicit_formatter_handles_arrays
152
+ posts = Models.all
153
+ serializable_resource = serializable(posts, adapter: :json_api)
73
154
 
74
- posts = Models.all
75
- serializable_resource = serializable(posts, adapter: :json_api)
155
+ with_adapter :json_api do
156
+ get '/grape/render_array_with_implicit_formatter'
157
+ end
158
+
159
+ assert last_response.ok?
160
+ assert_equal serializable_resource.to_json, last_response.body
161
+ ensure
162
+ Models.reset_all
163
+ end
76
164
 
77
- assert last_response.ok?
78
- assert_equal serializable_resource.to_json, last_response.body
79
- ensure
80
- ARModels::Post.delete_all
165
+ def test_implicit_formatter_handles_collections
166
+ with_adapter :json_api do
167
+ get '/grape/render_collection_with_implicit_formatter'
168
+ end
169
+
170
+ representation = JSON.parse(last_response.body)
171
+ assert last_response.ok?
172
+ assert representation.include?('data')
173
+ assert representation['data'].count == Models.collection_per
174
+ assert representation.include?('links')
175
+ assert representation['links'].count > 0
176
+ end
81
177
  end
82
178
  end
data/test/lint_test.rb CHANGED
@@ -30,7 +30,7 @@ module ActiveModel
30
30
  def errors
31
31
  end
32
32
 
33
- def self.human_attribute_name(attr, options = {})
33
+ def self.human_attribute_name(_, _ = {})
34
34
  end
35
35
 
36
36
  def self.lookup_ancestors
data/test/logger_test.rb CHANGED
@@ -1,18 +1,20 @@
1
1
  require 'test_helper'
2
2
 
3
- class ActiveModelSerializers::LoggerTest < ActiveSupport::TestCase
4
- def test_logger_is_set_to_action_controller_logger_when_initializer_runs
5
- assert_equal $action_controller_logger, ActionController::Base.logger # rubocop:disable Style/GlobalVars
6
- end
3
+ module ActiveModelSerializers
4
+ class LoggerTest < ActiveSupport::TestCase
5
+ def test_logger_is_set_to_action_controller_logger_when_initializer_runs
6
+ assert_equal $action_controller_logger, ActionController::Base.logger # rubocop:disable Style/GlobalVars
7
+ end
7
8
 
8
- def test_logger_can_be_set
9
- original_logger = ActiveModelSerializers.logger
10
- logger = Logger.new(STDOUT)
9
+ def test_logger_can_be_set
10
+ original_logger = ActiveModelSerializers.logger
11
+ logger = Logger.new(STDOUT)
11
12
 
12
- ActiveModelSerializers.logger = logger
13
+ ActiveModelSerializers.logger = logger
13
14
 
14
- assert_equal ActiveModelSerializers.logger, logger
15
- ensure
16
- ActiveModelSerializers.logger = original_logger
15
+ assert_equal ActiveModelSerializers.logger, logger
16
+ ensure
17
+ ActiveModelSerializers.logger = original_logger
18
+ end
17
19
  end
18
20
  end