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