active_model_serializers 0.10.9 → 0.10.13

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 (161) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +41 -2
  3. data/README.md +18 -19
  4. data/lib/action_controller/serialization.rb +9 -1
  5. data/lib/active_model/serializer/collection_serializer.rb +11 -2
  6. data/lib/active_model/serializer/concerns/caching.rb +2 -1
  7. data/lib/active_model/serializer/fieldset.rb +1 -1
  8. data/lib/active_model/serializer/reflection.rb +4 -4
  9. data/lib/active_model/serializer/version.rb +1 -1
  10. data/lib/active_model/serializer.rb +13 -4
  11. data/lib/active_model_serializers/adapter/attributes.rb +21 -0
  12. data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +5 -1
  13. data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +1 -1
  14. data/lib/active_model_serializers/model/caching.rb +26 -0
  15. metadata +20 -292
  16. data/.github/ISSUE_TEMPLATE.md +0 -29
  17. data/.github/PULL_REQUEST_TEMPLATE.md +0 -15
  18. data/.gitignore +0 -35
  19. data/.rubocop.yml +0 -109
  20. data/.simplecov +0 -110
  21. data/.travis.yml +0 -63
  22. data/CODE_OF_CONDUCT.md +0 -74
  23. data/CONTRIBUTING.md +0 -105
  24. data/Gemfile +0 -74
  25. data/Rakefile +0 -76
  26. data/active_model_serializers.gemspec +0 -64
  27. data/appveyor.yml +0 -28
  28. data/bin/bench +0 -171
  29. data/bin/bench_regression +0 -316
  30. data/bin/rubocop +0 -38
  31. data/bin/serve_benchmark +0 -39
  32. data/docs/README.md +0 -41
  33. data/docs/STYLE.md +0 -58
  34. data/docs/general/adapters.md +0 -269
  35. data/docs/general/caching.md +0 -58
  36. data/docs/general/configuration_options.md +0 -185
  37. data/docs/general/deserialization.md +0 -100
  38. data/docs/general/fields.md +0 -31
  39. data/docs/general/getting_started.md +0 -133
  40. data/docs/general/instrumentation.md +0 -40
  41. data/docs/general/key_transforms.md +0 -40
  42. data/docs/general/logging.md +0 -21
  43. data/docs/general/rendering.md +0 -293
  44. data/docs/general/serializers.md +0 -495
  45. data/docs/how-open-source-maintained.jpg +0 -0
  46. data/docs/howto/add_pagination_links.md +0 -138
  47. data/docs/howto/add_relationship_links.md +0 -140
  48. data/docs/howto/add_root_key.md +0 -62
  49. data/docs/howto/grape_integration.md +0 -42
  50. data/docs/howto/outside_controller_use.md +0 -66
  51. data/docs/howto/passing_arbitrary_options.md +0 -27
  52. data/docs/howto/serialize_poro.md +0 -73
  53. data/docs/howto/test.md +0 -154
  54. data/docs/howto/upgrade_from_0_8_to_0_10.md +0 -265
  55. data/docs/integrations/ember-and-json-api.md +0 -147
  56. data/docs/integrations/grape.md +0 -19
  57. data/docs/jsonapi/errors.md +0 -56
  58. data/docs/jsonapi/schema/schema.json +0 -366
  59. data/docs/jsonapi/schema.md +0 -151
  60. data/docs/rfcs/0000-namespace.md +0 -106
  61. data/docs/rfcs/template.md +0 -15
  62. data/test/action_controller/adapter_selector_test.rb +0 -64
  63. data/test/action_controller/explicit_serializer_test.rb +0 -137
  64. data/test/action_controller/json/include_test.rb +0 -248
  65. data/test/action_controller/json_api/deserialization_test.rb +0 -114
  66. data/test/action_controller/json_api/errors_test.rb +0 -42
  67. data/test/action_controller/json_api/fields_test.rb +0 -68
  68. data/test/action_controller/json_api/linked_test.rb +0 -204
  69. data/test/action_controller/json_api/pagination_test.rb +0 -126
  70. data/test/action_controller/json_api/transform_test.rb +0 -191
  71. data/test/action_controller/lookup_proc_test.rb +0 -51
  72. data/test/action_controller/namespace_lookup_test.rb +0 -234
  73. data/test/action_controller/serialization_scope_name_test.rb +0 -237
  74. data/test/action_controller/serialization_test.rb +0 -480
  75. data/test/active_model_serializers/adapter_for_test.rb +0 -210
  76. data/test/active_model_serializers/json_pointer_test.rb +0 -24
  77. data/test/active_model_serializers/logging_test.rb +0 -79
  78. data/test/active_model_serializers/model_test.rb +0 -144
  79. data/test/active_model_serializers/railtie_test_isolated.rb +0 -70
  80. data/test/active_model_serializers/register_jsonapi_renderer_test_isolated.rb +0 -163
  81. data/test/active_model_serializers/serialization_context_test_isolated.rb +0 -73
  82. data/test/active_model_serializers/test/schema_test.rb +0 -133
  83. data/test/active_model_serializers/test/serializer_test.rb +0 -64
  84. data/test/active_record_test.rb +0 -11
  85. data/test/adapter/attributes_test.rb +0 -42
  86. data/test/adapter/deprecation_test.rb +0 -102
  87. data/test/adapter/json/belongs_to_test.rb +0 -47
  88. data/test/adapter/json/collection_test.rb +0 -106
  89. data/test/adapter/json/has_many_test.rb +0 -55
  90. data/test/adapter/json/transform_test.rb +0 -95
  91. data/test/adapter/json_api/belongs_to_test.rb +0 -157
  92. data/test/adapter/json_api/collection_test.rb +0 -98
  93. data/test/adapter/json_api/errors_test.rb +0 -78
  94. data/test/adapter/json_api/fields_test.rb +0 -98
  95. data/test/adapter/json_api/has_many_explicit_serializer_test.rb +0 -98
  96. data/test/adapter/json_api/has_many_test.rb +0 -175
  97. data/test/adapter/json_api/has_one_test.rb +0 -82
  98. data/test/adapter/json_api/include_data_if_sideloaded_test.rb +0 -215
  99. data/test/adapter/json_api/json_api_test.rb +0 -35
  100. data/test/adapter/json_api/linked_test.rb +0 -415
  101. data/test/adapter/json_api/links_test.rb +0 -112
  102. data/test/adapter/json_api/pagination_links_test.rb +0 -208
  103. data/test/adapter/json_api/parse_test.rb +0 -139
  104. data/test/adapter/json_api/relationship_test.rb +0 -399
  105. data/test/adapter/json_api/resource_meta_test.rb +0 -102
  106. data/test/adapter/json_api/toplevel_jsonapi_test.rb +0 -84
  107. data/test/adapter/json_api/transform_test.rb +0 -514
  108. data/test/adapter/json_api/type_test.rb +0 -195
  109. data/test/adapter/json_test.rb +0 -48
  110. data/test/adapter/null_test.rb +0 -24
  111. data/test/adapter/polymorphic_test.rb +0 -220
  112. data/test/adapter_test.rb +0 -69
  113. data/test/array_serializer_test.rb +0 -24
  114. data/test/benchmark/app.rb +0 -67
  115. data/test/benchmark/benchmarking_support.rb +0 -69
  116. data/test/benchmark/bm_active_record.rb +0 -83
  117. data/test/benchmark/bm_adapter.rb +0 -40
  118. data/test/benchmark/bm_caching.rb +0 -121
  119. data/test/benchmark/bm_lookup_chain.rb +0 -85
  120. data/test/benchmark/bm_transform.rb +0 -47
  121. data/test/benchmark/config.ru +0 -3
  122. data/test/benchmark/controllers.rb +0 -85
  123. data/test/benchmark/fixtures.rb +0 -221
  124. data/test/cache_test.rb +0 -717
  125. data/test/collection_serializer_test.rb +0 -129
  126. data/test/fixtures/active_record.rb +0 -115
  127. data/test/fixtures/poro.rb +0 -227
  128. data/test/generators/scaffold_controller_generator_test.rb +0 -26
  129. data/test/generators/serializer_generator_test.rb +0 -77
  130. data/test/grape_test.rb +0 -198
  131. data/test/lint_test.rb +0 -51
  132. data/test/logger_test.rb +0 -22
  133. data/test/poro_test.rb +0 -11
  134. data/test/serializable_resource_test.rb +0 -81
  135. data/test/serializers/association_macros_test.rb +0 -39
  136. data/test/serializers/associations_test.rb +0 -520
  137. data/test/serializers/attribute_test.rb +0 -155
  138. data/test/serializers/attributes_test.rb +0 -54
  139. data/test/serializers/caching_configuration_test_isolated.rb +0 -172
  140. data/test/serializers/configuration_test.rb +0 -34
  141. data/test/serializers/fieldset_test.rb +0 -16
  142. data/test/serializers/meta_test.rb +0 -204
  143. data/test/serializers/options_test.rb +0 -34
  144. data/test/serializers/read_attribute_for_serialization_test.rb +0 -81
  145. data/test/serializers/reflection_test.rb +0 -481
  146. data/test/serializers/root_test.rb +0 -23
  147. data/test/serializers/serialization_test.rb +0 -57
  148. data/test/serializers/serializer_for_test.rb +0 -138
  149. data/test/serializers/serializer_for_with_namespace_test.rb +0 -90
  150. data/test/support/custom_schemas/active_model_serializers/test/schema_test/my/index.json +0 -6
  151. data/test/support/isolated_unit.rb +0 -86
  152. data/test/support/rails5_shims.rb +0 -55
  153. data/test/support/rails_app.rb +0 -40
  154. data/test/support/schemas/active_model_serializers/test/schema_test/my/index.json +0 -6
  155. data/test/support/schemas/active_model_serializers/test/schema_test/my/show.json +0 -6
  156. data/test/support/schemas/custom/show.json +0 -7
  157. data/test/support/schemas/hyper_schema.json +0 -93
  158. data/test/support/schemas/render_using_json_api.json +0 -43
  159. data/test/support/schemas/simple_json_pointers.json +0 -10
  160. data/test/support/serialization_testing.rb +0 -81
  161. data/test/test_helper.rb +0 -72
data/test/cache_test.rb DELETED
@@ -1,717 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'test_helper'
4
- require 'tmpdir'
5
- require 'tempfile'
6
-
7
- module ActiveModelSerializers
8
- class CacheTest < ActiveSupport::TestCase
9
- class Article < ::Model
10
- attributes :title
11
- # To confirm error is raised when cache_key is not set and cache_key option not passed to cache
12
- undef_method :cache_key
13
- end
14
- class ArticleSerializer < ActiveModel::Serializer
15
- cache only: [:place], skip_digest: true
16
- attributes :title
17
- end
18
-
19
- class Author < ::Model
20
- attributes :id, :name
21
- associations :posts, :bio, :roles
22
- end
23
- # Instead of a primitive cache key (i.e. a string), this class
24
- # returns a list of objects that require to be expanded themselves.
25
- class AuthorWithExpandableCacheElements < Author
26
- # For the test purposes it's important that #to_s for HasCacheKey differs
27
- # between instances, hence not a Struct.
28
- class HasCacheKey
29
- attr_reader :cache_key
30
- def initialize(cache_key)
31
- @cache_key = cache_key
32
- end
33
-
34
- def to_s
35
- "HasCacheKey##{object_id}"
36
- end
37
- end
38
-
39
- def cache_key
40
- [
41
- HasCacheKey.new(name),
42
- HasCacheKey.new(id)
43
- ]
44
- end
45
- end
46
- class UncachedAuthor < Author
47
- # To confirm cache_key is set using updated_at and cache_key option passed to cache
48
- undef_method :cache_key
49
- end
50
- class AuthorSerializer < ActiveModel::Serializer
51
- cache key: 'writer', skip_digest: true
52
- attributes :id, :name
53
-
54
- has_many :posts
55
- has_many :roles
56
- has_one :bio
57
- end
58
- class AuthorSerializerWithCache < ActiveModel::Serializer
59
- cache
60
-
61
- attributes :name
62
- end
63
-
64
- class Blog < ::Model
65
- attributes :name
66
- associations :writer
67
- end
68
- class BlogSerializer < ActiveModel::Serializer
69
- cache key: 'blog'
70
- attributes :id, :name
71
-
72
- belongs_to :writer
73
- end
74
-
75
- class Comment < ::Model
76
- attributes :id, :body
77
- associations :post, :author
78
-
79
- # Uses a custom non-time-based cache key
80
- def cache_key
81
- "comment/#{id}"
82
- end
83
- end
84
- class CommentSerializer < ActiveModel::Serializer
85
- cache expires_in: 1.day, skip_digest: true
86
- attributes :id, :body
87
- belongs_to :post
88
- belongs_to :author
89
- end
90
-
91
- class Post < ::Model
92
- attributes :id, :title, :body
93
- associations :author, :comments, :blog
94
- end
95
- class PostSerializer < ActiveModel::Serializer
96
- cache key: 'post', expires_in: 0.1, skip_digest: true
97
- attributes :id, :title, :body
98
-
99
- has_many :comments
100
- belongs_to :blog
101
- belongs_to :author
102
- end
103
-
104
- class Role < ::Model
105
- attributes :name, :description, :special_attribute
106
- associations :author
107
- end
108
- class RoleSerializer < ActiveModel::Serializer
109
- cache only: [:name, :slug], skip_digest: true
110
- attributes :id, :name, :description
111
- attribute :friendly_id, key: :slug
112
- belongs_to :author
113
-
114
- def friendly_id
115
- "#{object.name}-#{object.id}"
116
- end
117
- end
118
- class InheritedRoleSerializer < RoleSerializer
119
- cache key: 'inherited_role', only: [:name, :special_attribute]
120
- attribute :special_attribute
121
- end
122
-
123
- setup do
124
- cache_store.clear
125
- @comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
126
- @post = Post.new(id: 'post', title: 'New Post', body: 'Body')
127
- @bio = Bio.new(id: 1, content: 'AMS Contributor')
128
- @author = Author.new(id: 'author', name: 'Joao M. D. Moura')
129
- @blog = Blog.new(id: 999, name: 'Custom blog', writer: @author)
130
- @role = Role.new(name: 'Great Author')
131
- @location = Location.new(lat: '-23.550520', lng: '-46.633309')
132
- @place = Place.new(name: 'Amazing Place')
133
- @author.posts = [@post]
134
- @author.roles = [@role]
135
- @role.author = @author
136
- @author.bio = @bio
137
- @bio.author = @author
138
- @post.comments = [@comment]
139
- @post.author = @author
140
- @comment.post = @post
141
- @comment.author = @author
142
- @post.blog = @blog
143
- @location.place = @place
144
-
145
- @location_serializer = LocationSerializer.new(@location)
146
- @bio_serializer = BioSerializer.new(@bio)
147
- @role_serializer = RoleSerializer.new(@role)
148
- @post_serializer = PostSerializer.new(@post)
149
- @author_serializer = AuthorSerializer.new(@author)
150
- @comment_serializer = CommentSerializer.new(@comment)
151
- @blog_serializer = BlogSerializer.new(@blog)
152
- end
153
-
154
- def test_expiring_of_cache_at_update_of_record
155
- original_cache_versioning = :none
156
-
157
- if ARModels::Author.respond_to?(:cache_versioning)
158
- original_cache_versioning = ARModels::Author.cache_versioning
159
- ARModels::Author.cache_versioning = true
160
- end
161
-
162
- author = ARModels::Author.create(name: 'Foo')
163
- author_json = AuthorSerializerWithCache.new(author).as_json
164
-
165
- assert_equal 'Foo', author_json[:name]
166
-
167
- author.update_attributes(name: 'Bar')
168
- author_json = AuthorSerializerWithCache.new(author).as_json
169
-
170
- expected = 'Bar'
171
- actual = author_json[:name]
172
- if ENV['APPVEYOR'] && actual != expected
173
- skip('Cache expiration tests sometimes fail on Appveyor. FIXME :)')
174
- else
175
- assert_equal expected, actual
176
- end
177
- ensure
178
- ARModels::Author.cache_versioning = original_cache_versioning unless original_cache_versioning == :none
179
- end
180
-
181
- def test_cache_expiration_in_collection_on_update_of_record
182
- original_cache_versioning = :none
183
-
184
- if ARModels::Author.respond_to?(:cache_versioning)
185
- original_cache_versioning = ARModels::Author.cache_versioning
186
- ARModels::Author.cache_versioning = true
187
- end
188
-
189
- foo = 'Foo'
190
- foo2 = 'Foo2'
191
- author = ARModels::Author.create(name: foo)
192
- author2 = ARModels::Author.create(name: foo2)
193
- author_collection = [author, author, author2]
194
-
195
- collection_json = render_object_with_cache(author_collection, each_serializer: AuthorSerializerWithCache)
196
- actual = collection_json
197
- expected = [{ name: foo }, { name: foo }, { name: foo2 }]
198
- if ENV['APPVEYOR'] && actual != expected
199
- skip('Cache expiration tests sometimes fail on Appveyor. FIXME :)')
200
- else
201
- assert_equal expected, actual
202
- end
203
-
204
- bar = 'Bar'
205
- author.update!(name: bar)
206
-
207
- collection_json = render_object_with_cache(author_collection, each_serializer: AuthorSerializerWithCache)
208
- assert_equal [{ name: bar }, { name: bar }, { name: foo2 }], collection_json
209
- ensure
210
- ARModels::Author.cache_versioning = original_cache_versioning unless original_cache_versioning == :none
211
- end
212
-
213
- def test_explicit_cache_store
214
- default_store = Class.new(ActiveModel::Serializer) do
215
- cache
216
- end
217
- explicit_store = Class.new(ActiveModel::Serializer) do
218
- cache cache_store: ActiveSupport::Cache::FileStore
219
- end
220
-
221
- assert ActiveSupport::Cache::MemoryStore, ActiveModelSerializers.config.cache_store
222
- assert ActiveSupport::Cache::MemoryStore, default_store.cache_store
223
- assert ActiveSupport::Cache::FileStore, explicit_store.cache_store
224
- end
225
-
226
- def test_inherited_cache_configuration
227
- inherited_serializer = Class.new(PostSerializer)
228
-
229
- assert_equal PostSerializer._cache_key, inherited_serializer._cache_key
230
- assert_equal PostSerializer._cache_options, inherited_serializer._cache_options
231
- end
232
-
233
- def test_override_cache_configuration
234
- inherited_serializer = Class.new(PostSerializer) do
235
- cache key: 'new-key'
236
- end
237
-
238
- assert_equal PostSerializer._cache_key, 'post'
239
- assert_equal inherited_serializer._cache_key, 'new-key'
240
- end
241
-
242
- def test_cache_definition
243
- assert_equal(cache_store, @post_serializer.class._cache)
244
- assert_equal(cache_store, @author_serializer.class._cache)
245
- assert_equal(cache_store, @comment_serializer.class._cache)
246
- end
247
-
248
- def test_cache_key_definition
249
- assert_equal('post', @post_serializer.class._cache_key)
250
- assert_equal('writer', @author_serializer.class._cache_key)
251
- assert_nil(@comment_serializer.class._cache_key)
252
- end
253
-
254
- def test_cache_key_interpolation_with_updated_at_when_cache_key_is_not_defined_on_object
255
- uncached_author = UncachedAuthor.new(name: 'Joao M. D. Moura')
256
- uncached_author_serializer = AuthorSerializer.new(uncached_author)
257
-
258
- render_object_with_cache(uncached_author)
259
- 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')}"
260
- key = "#{key}/#{adapter.cache_key}"
261
- assert_equal(uncached_author_serializer.attributes.to_json, cache_store.fetch(key).to_json)
262
- end
263
-
264
- def test_cache_key_expansion
265
- author = AuthorWithExpandableCacheElements.new(id: 10, name: 'hello')
266
- same_author = AuthorWithExpandableCacheElements.new(id: 10, name: 'hello')
267
- diff_author = AuthorWithExpandableCacheElements.new(id: 11, name: 'hello')
268
-
269
- author_serializer = AuthorSerializer.new(author)
270
- same_author_serializer = AuthorSerializer.new(same_author)
271
- diff_author_serializer = AuthorSerializer.new(diff_author)
272
- adapter = AuthorSerializer.serialization_adapter_instance
273
-
274
- assert_equal(author_serializer.cache_key(adapter), same_author_serializer.cache_key(adapter))
275
- refute_equal(author_serializer.cache_key(adapter), diff_author_serializer.cache_key(adapter))
276
- end
277
-
278
- def test_default_cache_key_fallback
279
- render_object_with_cache(@comment)
280
- key = "#{@comment.cache_key}/#{adapter.cache_key}"
281
- assert_equal(@comment_serializer.attributes.to_json, cache_store.fetch(key).to_json)
282
- end
283
-
284
- def test_error_is_raised_if_cache_key_is_not_defined_on_object_or_passed_as_cache_option
285
- article = Article.new(title: 'Must Read')
286
- e = assert_raises ActiveModel::Serializer::UndefinedCacheKey do
287
- render_object_with_cache(article)
288
- end
289
- assert_match(/ActiveModelSerializers::CacheTest::Article must define #cache_key, or the 'key:' option must be passed into 'ActiveModelSerializers::CacheTest::ArticleSerializer.cache'/, e.message)
290
- end
291
-
292
- def test_cache_options_definition
293
- assert_equal({ expires_in: 0.1, skip_digest: true }, @post_serializer.class._cache_options)
294
- assert_nil(@blog_serializer.class._cache_options)
295
- assert_equal({ expires_in: 1.day, skip_digest: true }, @comment_serializer.class._cache_options)
296
- end
297
-
298
- def test_fragment_cache_definition
299
- assert_equal([:name, :slug], @role_serializer.class._cache_only)
300
- assert_equal([:content], @bio_serializer.class._cache_except)
301
- end
302
-
303
- def test_associations_separately_cache
304
- cache_store.clear
305
- assert_nil(cache_store.fetch(@post.cache_key))
306
- assert_nil(cache_store.fetch(@comment.cache_key))
307
-
308
- Timecop.freeze(Time.current) do
309
- render_object_with_cache(@post)
310
-
311
- key = "#{@post.cache_key}/#{adapter.cache_key}"
312
- assert_equal(@post_serializer.attributes, cache_store.fetch(key))
313
- key = "#{@comment.cache_key}/#{adapter.cache_key}"
314
- assert_equal(@comment_serializer.attributes, cache_store.fetch(key))
315
- end
316
- end
317
-
318
- def test_associations_cache_when_updated
319
- Timecop.freeze(Time.current) do
320
- # Generate a new Cache of Post object and each objects related to it.
321
- render_object_with_cache(@post)
322
-
323
- # Check if it cached the objects separately
324
- key = "#{@post.cache_key}/#{adapter.cache_key}"
325
- assert_equal(@post_serializer.attributes, cache_store.fetch(key))
326
- key = "#{@comment.cache_key}/#{adapter.cache_key}"
327
- assert_equal(@comment_serializer.attributes, cache_store.fetch(key))
328
-
329
- # Simulating update on comments relationship with Post
330
- new_comment = Comment.new(id: 2567, body: 'ZOMG A NEW COMMENT')
331
- new_comment_serializer = CommentSerializer.new(new_comment)
332
- @post.comments = [new_comment]
333
-
334
- # Ask for the serialized object
335
- render_object_with_cache(@post)
336
-
337
- # Check if the the new comment was cached
338
- key = "#{new_comment.cache_key}/#{adapter.cache_key}"
339
- assert_equal(new_comment_serializer.attributes, cache_store.fetch(key))
340
- key = "#{@post.cache_key}/#{adapter.cache_key}"
341
- assert_equal(@post_serializer.attributes, cache_store.fetch(key))
342
- end
343
- end
344
-
345
- def test_fragment_fetch_with_virtual_associations
346
- expected_result = {
347
- id: @location.id,
348
- lat: @location.lat,
349
- lng: @location.lng,
350
- address: 'Nowhere'
351
- }
352
-
353
- hash = render_object_with_cache(@location)
354
-
355
- assert_equal(hash, expected_result)
356
- key = "#{@location.cache_key}/#{adapter.cache_key}"
357
- assert_equal({ address: 'Nowhere' }, cache_store.fetch(key))
358
- end
359
-
360
- def test_fragment_cache_with_inheritance
361
- inherited = render_object_with_cache(@role, serializer: InheritedRoleSerializer)
362
- base = render_object_with_cache(@role)
363
-
364
- assert_includes(inherited.keys, :special_attribute)
365
- refute_includes(base.keys, :special_attribute)
366
- end
367
-
368
- def test_uses_adapter_in_cache_key
369
- render_object_with_cache(@post)
370
- key = "#{@post.cache_key}/#{adapter.class.to_s.demodulize.underscore}"
371
- assert_equal(@post_serializer.attributes, cache_store.fetch(key))
372
- end
373
-
374
- # Based on original failing test by @kevintyll
375
- # rubocop:disable Metrics/AbcSize
376
- def test_a_serializer_rendered_by_two_adapter_returns_differently_fetch_attributes
377
- Object.const_set(:Alert, Class.new(ActiveModelSerializers::Model) do
378
- attributes :id, :status, :resource, :started_at, :ended_at, :updated_at, :created_at
379
- end)
380
- Object.const_set(:UncachedAlertSerializer, Class.new(ActiveModel::Serializer) do
381
- attributes :id, :status, :resource, :started_at, :ended_at, :updated_at, :created_at
382
- end)
383
- Object.const_set(:AlertSerializer, Class.new(UncachedAlertSerializer) do
384
- cache
385
- end)
386
-
387
- alert = Alert.new(
388
- id: 1,
389
- status: 'fail',
390
- resource: 'resource-1',
391
- started_at: Time.new(2016, 3, 31, 21, 36, 35, 0),
392
- ended_at: nil,
393
- updated_at: Time.new(2016, 3, 31, 21, 27, 35, 0),
394
- created_at: Time.new(2016, 3, 31, 21, 37, 35, 0)
395
- )
396
-
397
- expected_fetch_attributes = {
398
- id: 1,
399
- status: 'fail',
400
- resource: 'resource-1',
401
- started_at: alert.started_at,
402
- ended_at: nil,
403
- updated_at: alert.updated_at,
404
- created_at: alert.created_at
405
- }.with_indifferent_access
406
- expected_cached_jsonapi_attributes = {
407
- id: '1',
408
- type: 'alerts',
409
- attributes: {
410
- status: 'fail',
411
- resource: 'resource-1',
412
- started_at: alert.started_at,
413
- ended_at: nil,
414
- updated_at: alert.updated_at,
415
- created_at: alert.created_at
416
- }
417
- }.with_indifferent_access
418
-
419
- # Assert attributes are serialized correctly
420
- serializable_alert = serializable(alert, serializer: AlertSerializer, adapter: :attributes)
421
- attributes_serialization = serializable_alert.as_json.with_indifferent_access
422
- assert_equal expected_fetch_attributes, alert.attributes
423
- assert_equal alert.attributes, attributes_serialization
424
- attributes_cache_key = serializable_alert.adapter.serializer.cache_key(serializable_alert.adapter)
425
- assert_equal attributes_serialization, cache_store.fetch(attributes_cache_key).with_indifferent_access
426
-
427
- serializable_alert = serializable(alert, serializer: AlertSerializer, adapter: :json_api)
428
- jsonapi_cache_key = serializable_alert.adapter.serializer.cache_key(serializable_alert.adapter)
429
- # Assert cache keys differ
430
- refute_equal attributes_cache_key, jsonapi_cache_key
431
- # Assert (cached) serializations differ
432
- jsonapi_serialization = serializable_alert.as_json
433
- assert_equal alert.status, jsonapi_serialization.fetch(:data).fetch(:attributes).fetch(:status)
434
- serializable_alert = serializable(alert, serializer: UncachedAlertSerializer, adapter: :json_api)
435
- assert_equal serializable_alert.as_json, jsonapi_serialization
436
-
437
- cached_serialization = cache_store.fetch(jsonapi_cache_key).with_indifferent_access
438
- assert_equal expected_cached_jsonapi_attributes, cached_serialization
439
- ensure
440
- Object.send(:remove_const, :Alert)
441
- Object.send(:remove_const, :AlertSerializer)
442
- Object.send(:remove_const, :UncachedAlertSerializer)
443
- end
444
- # rubocop:enable Metrics/AbcSize
445
-
446
- def test_uses_file_digest_in_cache_key
447
- render_object_with_cache(@blog)
448
- file_digest = Digest::MD5.hexdigest(File.open(__FILE__).read)
449
- key = "#{@blog.cache_key}/#{adapter.cache_key}/#{file_digest}"
450
- assert_equal(@blog_serializer.attributes, cache_store.fetch(key))
451
- end
452
-
453
- def test_cache_digest_definition
454
- file_digest = Digest::MD5.hexdigest(File.open(__FILE__).read)
455
- assert_equal(file_digest, @post_serializer.class._cache_digest)
456
- end
457
-
458
- def test_object_cache_keys
459
- serializable = ActiveModelSerializers::SerializableResource.new([@comment, @comment])
460
- include_directive = JSONAPI::IncludeDirective.new('*', allow_wildcard: true)
461
-
462
- actual = ActiveModel::Serializer.object_cache_keys(serializable.adapter.serializer, serializable.adapter, include_directive)
463
-
464
- assert_equal 3, actual.size
465
- expected_key = "comment/1/#{serializable.adapter.cache_key}"
466
- assert actual.any? { |key| key == expected_key }, "actual '#{actual}' should include #{expected_key}"
467
- expected_key = %r{post/post-\d+}
468
- assert actual.any? { |key| key =~ expected_key }, "actual '#{actual}' should match '#{expected_key}'"
469
- expected_key = %r{author/author-\d+}
470
- assert actual.any? { |key| key =~ expected_key }, "actual '#{actual}' should match '#{expected_key}'"
471
- end
472
-
473
- # rubocop:disable Metrics/AbcSize
474
- def test_fetch_attributes_from_cache
475
- serializers = ActiveModel::Serializer::CollectionSerializer.new([@comment, @comment])
476
-
477
- Timecop.freeze(Time.current) do
478
- render_object_with_cache(@comment)
479
-
480
- options = {}
481
- adapter_options = {}
482
- adapter_instance = ActiveModelSerializers::Adapter::Attributes.new(serializers, adapter_options)
483
- serializers.serializable_hash(adapter_options, options, adapter_instance)
484
- cached_attributes = options.fetch(:cached_attributes).with_indifferent_access
485
-
486
- include_directive = ActiveModelSerializers.default_include_directive
487
- manual_cached_attributes = ActiveModel::Serializer.cache_read_multi(serializers, adapter_instance, include_directive).with_indifferent_access
488
- assert_equal manual_cached_attributes, cached_attributes
489
-
490
- assert_equal cached_attributes["#{@comment.cache_key}/#{adapter_instance.cache_key}"], Comment.new(id: 1, body: 'ZOMG A COMMENT').attributes
491
- assert_equal cached_attributes["#{@comment.post.cache_key}/#{adapter_instance.cache_key}"], Post.new(id: 'post', title: 'New Post', body: 'Body').attributes
492
-
493
- writer = @comment.post.blog.writer
494
- writer_cache_key = writer.cache_key
495
- assert_equal cached_attributes["#{writer_cache_key}/#{adapter_instance.cache_key}"], Author.new(id: 'author', name: 'Joao M. D. Moura').attributes
496
- end
497
- end
498
- # rubocop:enable Metrics/AbcSize
499
-
500
- def test_cache_read_multi_with_fragment_cache_enabled
501
- post_serializer = Class.new(ActiveModel::Serializer) do
502
- cache except: [:body]
503
- end
504
-
505
- serializers = ActiveModel::Serializer::CollectionSerializer.new([@post, @post], serializer: post_serializer)
506
-
507
- Timecop.freeze(Time.current) do
508
- # Warming up.
509
- options = {}
510
- adapter_options = {}
511
- adapter_instance = ActiveModelSerializers::Adapter::Attributes.new(serializers, adapter_options)
512
- serializers.serializable_hash(adapter_options, options, adapter_instance)
513
-
514
- # Should find something with read_multi now
515
- options = {}
516
- serializers.serializable_hash(adapter_options, options, adapter_instance)
517
- cached_attributes = options.fetch(:cached_attributes)
518
-
519
- include_directive = ActiveModelSerializers.default_include_directive
520
- manual_cached_attributes = ActiveModel::Serializer.cache_read_multi(serializers, adapter_instance, include_directive)
521
-
522
- refute_equal 0, cached_attributes.size
523
- refute_equal 0, manual_cached_attributes.size
524
- assert_equal manual_cached_attributes, cached_attributes
525
- end
526
- end
527
-
528
- def test_serializer_file_path_on_nix
529
- path = '/Users/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb'
530
- caller_line = "#{path}:1:in `<top (required)>'"
531
- assert_equal caller_line[ActiveModel::Serializer::CALLER_FILE], path
532
- end
533
-
534
- def test_serializer_file_path_on_windows
535
- path = 'c:/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb'
536
- caller_line = "#{path}:1:in `<top (required)>'"
537
- assert_equal caller_line[ActiveModel::Serializer::CALLER_FILE], path
538
- end
539
-
540
- def test_serializer_file_path_with_space
541
- path = '/Users/git/ember js/ember-crm-backend/app/serializers/lead_serializer.rb'
542
- caller_line = "#{path}:1:in `<top (required)>'"
543
- assert_equal caller_line[ActiveModel::Serializer::CALLER_FILE], path
544
- end
545
-
546
- def test_serializer_file_path_with_submatch
547
- # The submatch in the path ensures we're using a correctly greedy regexp.
548
- path = '/Users/git/ember js/ember:123:in x/app/serializers/lead_serializer.rb'
549
- caller_line = "#{path}:1:in `<top (required)>'"
550
- assert_equal caller_line[ActiveModel::Serializer::CALLER_FILE], path
551
- end
552
-
553
- def test_digest_caller_file
554
- contents = "puts 'AMS rocks'!"
555
- dir = Dir.mktmpdir('space char')
556
- file = Tempfile.new('some_ruby.rb', dir)
557
- file.write(contents)
558
- path = file.path
559
- caller_line = "#{path}:1:in `<top (required)>'"
560
- file.close
561
- assert_equal ActiveModel::Serializer.digest_caller_file(caller_line), Digest::MD5.hexdigest(contents)
562
- ensure
563
- file.unlink
564
- FileUtils.remove_entry dir
565
- end
566
-
567
- def test_warn_on_serializer_not_defined_in_file
568
- called = false
569
- serializer = Class.new(ActiveModel::Serializer)
570
- assert_output(nil, /_cache_digest/) do
571
- serializer.digest_caller_file('')
572
- called = true
573
- end
574
- assert called
575
- end
576
-
577
- def test_cached_false_without_cache_store
578
- cached_serializer = build_cached_serializer do |serializer|
579
- serializer._cache = nil
580
- end
581
- refute cached_serializer.class.cache_enabled?
582
- end
583
-
584
- def test_cached_true_with_cache_store_and_without_cache_only_and_cache_except
585
- cached_serializer = build_cached_serializer do |serializer|
586
- serializer._cache = Object
587
- end
588
- assert cached_serializer.class.cache_enabled?
589
- end
590
-
591
- def test_cached_false_with_cache_store_and_with_cache_only
592
- cached_serializer = build_cached_serializer do |serializer|
593
- serializer._cache = Object
594
- serializer._cache_only = [:name]
595
- end
596
- refute cached_serializer.class.cache_enabled?
597
- end
598
-
599
- def test_cached_false_with_cache_store_and_with_cache_except
600
- cached_serializer = build_cached_serializer do |serializer|
601
- serializer._cache = Object
602
- serializer._cache_except = [:content]
603
- end
604
- refute cached_serializer.class.cache_enabled?
605
- end
606
-
607
- def test_fragment_cached_false_without_cache_store
608
- cached_serializer = build_cached_serializer do |serializer|
609
- serializer._cache = nil
610
- serializer._cache_only = [:name]
611
- end
612
- refute cached_serializer.class.fragment_cache_enabled?
613
- end
614
-
615
- def test_fragment_cached_true_with_cache_store_and_cache_only
616
- cached_serializer = build_cached_serializer do |serializer|
617
- serializer._cache = Object
618
- serializer._cache_only = [:name]
619
- end
620
- assert cached_serializer.class.fragment_cache_enabled?
621
- end
622
-
623
- def test_fragment_cached_true_with_cache_store_and_cache_except
624
- cached_serializer = build_cached_serializer do |serializer|
625
- serializer._cache = Object
626
- serializer._cache_except = [:content]
627
- end
628
- assert cached_serializer.class.fragment_cache_enabled?
629
- end
630
-
631
- def test_fragment_cached_false_with_cache_store_and_cache_except_and_cache_only
632
- cached_serializer = build_cached_serializer do |serializer|
633
- serializer._cache = Object
634
- serializer._cache_except = [:content]
635
- serializer._cache_only = [:name]
636
- end
637
- refute cached_serializer.class.fragment_cache_enabled?
638
- end
639
-
640
- def test_fragment_fetch_with_virtual_attributes
641
- author = Author.new(name: 'Joao M. D. Moura')
642
- role = Role.new(name: 'Great Author', description: nil)
643
- role.author = [author]
644
- role_serializer = RoleSerializer.new(role)
645
- adapter_instance = ActiveModelSerializers::Adapter.configured_adapter.new(role_serializer)
646
- expected_result = {
647
- id: role.id,
648
- description: role.description,
649
- slug: "#{role.name}-#{role.id}",
650
- name: role.name
651
- }
652
- cache_store.clear
653
-
654
- role_hash = role_serializer.fetch_attributes_fragment(adapter_instance)
655
- assert_equal(role_hash, expected_result)
656
-
657
- role.id = 'this has been updated'
658
- role.name = 'this was cached'
659
-
660
- role_hash = role_serializer.fetch_attributes_fragment(adapter_instance)
661
- assert_equal(expected_result.merge(id: role.id), role_hash)
662
- end
663
-
664
- def test_fragment_fetch_with_except
665
- adapter_instance = ActiveModelSerializers::Adapter.configured_adapter.new(@bio_serializer)
666
- expected_result = {
667
- id: @bio.id,
668
- rating: nil,
669
- content: @bio.content
670
- }
671
- cache_store.clear
672
-
673
- bio_hash = @bio_serializer.fetch_attributes_fragment(adapter_instance)
674
- assert_equal(expected_result, bio_hash)
675
-
676
- @bio.content = 'this has been updated'
677
- @bio.rating = 'this was cached'
678
-
679
- bio_hash = @bio_serializer.fetch_attributes_fragment(adapter_instance)
680
- assert_equal(expected_result.merge(content: @bio.content), bio_hash)
681
- end
682
-
683
- def test_fragment_fetch_with_namespaced_object
684
- @spam = Spam::UnrelatedLink.new(id: 'spam-id-1')
685
- @spam_serializer = Spam::UnrelatedLinkSerializer.new(@spam)
686
- adapter_instance = ActiveModelSerializers::Adapter.configured_adapter.new(@spam_serializer)
687
- @spam_hash = @spam_serializer.fetch_attributes_fragment(adapter_instance)
688
- expected_result = {
689
- id: @spam.id
690
- }
691
- assert_equal(@spam_hash, expected_result)
692
- end
693
-
694
- private
695
-
696
- def cache_store
697
- ActiveModelSerializers.config.cache_store
698
- end
699
-
700
- def build_cached_serializer
701
- serializer = Class.new(ActiveModel::Serializer)
702
- serializer._cache_key = nil
703
- serializer._cache_options = nil
704
- yield serializer if block_given?
705
- serializer.new(Object)
706
- end
707
-
708
- def render_object_with_cache(obj, options = {})
709
- @serializable_resource = serializable(obj, options)
710
- @serializable_resource.serializable_hash
711
- end
712
-
713
- def adapter
714
- @serializable_resource.adapter
715
- end
716
- end
717
- end