active_model_serializers 0.10.0 → 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 +239 -2
  3. data/README.md +171 -34
  4. data/lib/action_controller/serialization.rb +23 -3
  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 +4 -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 +10 -5
  13. data/lib/active_model/serializer/association.rb +64 -10
  14. data/lib/active_model/serializer/attribute.rb +2 -0
  15. data/lib/active_model/serializer/belongs_to_reflection.rb +6 -3
  16. data/lib/active_model/serializer/collection_serializer.rb +48 -13
  17. data/lib/active_model/serializer/{caching.rb → concerns/caching.rb} +89 -117
  18. data/lib/active_model/serializer/error_serializer.rb +13 -7
  19. data/lib/active_model/serializer/errors_serializer.rb +27 -20
  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 +5 -3
  23. data/lib/active_model/serializer/has_one_reflection.rb +3 -4
  24. data/lib/active_model/serializer/lazy_association.rb +99 -0
  25. data/lib/active_model/serializer/link.rb +23 -0
  26. data/lib/active_model/serializer/lint.rb +136 -130
  27. data/lib/active_model/serializer/null.rb +2 -0
  28. data/lib/active_model/serializer/reflection.rb +130 -65
  29. data/lib/active_model/serializer/version.rb +3 -1
  30. data/lib/active_model/serializer.rb +321 -86
  31. data/lib/active_model_serializers/adapter/attributes.rb +17 -57
  32. data/lib/active_model_serializers/adapter/base.rb +41 -39
  33. data/lib/active_model_serializers/adapter/json.rb +2 -0
  34. data/lib/active_model_serializers/adapter/json_api/deserialization.rb +4 -2
  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 +3 -1
  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 +52 -20
  40. data/lib/active_model_serializers/adapter/json_api/relationship.rb +77 -23
  41. data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +41 -10
  42. data/lib/active_model_serializers/adapter/json_api.rb +84 -65
  43. data/lib/active_model_serializers/adapter/null.rb +2 -0
  44. data/lib/active_model_serializers/adapter.rb +9 -1
  45. data/lib/active_model_serializers/callbacks.rb +2 -0
  46. data/lib/active_model_serializers/deprecate.rb +3 -2
  47. data/lib/active_model_serializers/deserialization.rb +4 -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 +82 -0
  51. data/lib/active_model_serializers/model/caching.rb +26 -0
  52. data/lib/active_model_serializers/model.rb +111 -28
  53. data/lib/active_model_serializers/railtie.rb +7 -1
  54. data/lib/active_model_serializers/register_jsonapi_renderer.rb +46 -31
  55. data/lib/active_model_serializers/serializable_resource.rb +10 -7
  56. data/lib/active_model_serializers/serialization_context.rb +12 -3
  57. data/lib/active_model_serializers/test/schema.rb +4 -2
  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 +35 -10
  61. data/lib/generators/rails/resource_override.rb +3 -1
  62. data/lib/generators/rails/serializer_generator.rb +6 -4
  63. data/lib/grape/active_model_serializers.rb +9 -5
  64. data/lib/grape/formatters/active_model_serializers.rb +21 -2
  65. data/lib/grape/helpers/active_model_serializers.rb +3 -0
  66. data/lib/tasks/rubocop.rake +55 -0
  67. metadata +104 -296
  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 -104
  72. data/.rubocop_todo.yml +0 -167
  73. data/.simplecov +0 -110
  74. data/.travis.yml +0 -43
  75. data/CONTRIBUTING.md +0 -105
  76. data/Gemfile +0 -53
  77. data/Rakefile +0 -103
  78. data/active_model_serializers.gemspec +0 -66
  79. data/appveyor.yml +0 -24
  80. data/bin/bench +0 -171
  81. data/bin/bench_regression +0 -316
  82. data/bin/serve_benchmark +0 -39
  83. data/docs/ARCHITECTURE.md +0 -126
  84. data/docs/README.md +0 -40
  85. data/docs/STYLE.md +0 -58
  86. data/docs/general/adapters.md +0 -245
  87. data/docs/general/caching.md +0 -52
  88. data/docs/general/configuration_options.md +0 -100
  89. data/docs/general/deserialization.md +0 -100
  90. data/docs/general/getting_started.md +0 -133
  91. data/docs/general/instrumentation.md +0 -40
  92. data/docs/general/key_transforms.md +0 -40
  93. data/docs/general/logging.md +0 -14
  94. data/docs/general/rendering.md +0 -255
  95. data/docs/general/serializers.md +0 -372
  96. data/docs/how-open-source-maintained.jpg +0 -0
  97. data/docs/howto/add_pagination_links.md +0 -139
  98. data/docs/howto/add_root_key.md +0 -51
  99. data/docs/howto/outside_controller_use.md +0 -58
  100. data/docs/howto/passing_arbitrary_options.md +0 -27
  101. data/docs/howto/serialize_poro.md +0 -32
  102. data/docs/howto/test.md +0 -152
  103. data/docs/integrations/ember-and-json-api.md +0 -112
  104. data/docs/integrations/grape.md +0 -19
  105. data/docs/jsonapi/errors.md +0 -56
  106. data/docs/jsonapi/schema/schema.json +0 -366
  107. data/docs/jsonapi/schema.md +0 -151
  108. data/docs/rfcs/0000-namespace.md +0 -106
  109. data/docs/rfcs/template.md +0 -15
  110. data/lib/active_model/serializer/associations.rb +0 -100
  111. data/lib/active_model/serializer/attributes.rb +0 -82
  112. data/lib/active_model/serializer/collection_reflection.rb +0 -7
  113. data/lib/active_model/serializer/configuration.rb +0 -35
  114. data/lib/active_model/serializer/include_tree.rb +0 -111
  115. data/lib/active_model/serializer/links.rb +0 -35
  116. data/lib/active_model/serializer/meta.rb +0 -29
  117. data/lib/active_model/serializer/singular_reflection.rb +0 -7
  118. data/lib/active_model/serializer/type.rb +0 -25
  119. data/lib/active_model_serializers/key_transform.rb +0 -70
  120. data/test/action_controller/adapter_selector_test.rb +0 -53
  121. data/test/action_controller/explicit_serializer_test.rb +0 -134
  122. data/test/action_controller/json/include_test.rb +0 -167
  123. data/test/action_controller/json_api/deserialization_test.rb +0 -112
  124. data/test/action_controller/json_api/errors_test.rb +0 -41
  125. data/test/action_controller/json_api/linked_test.rb +0 -197
  126. data/test/action_controller/json_api/pagination_test.rb +0 -116
  127. data/test/action_controller/json_api/transform_test.rb +0 -181
  128. data/test/action_controller/serialization_scope_name_test.rb +0 -229
  129. data/test/action_controller/serialization_test.rb +0 -469
  130. data/test/active_model_serializers/adapter_for_test.rb +0 -208
  131. data/test/active_model_serializers/json_pointer_test.rb +0 -20
  132. data/test/active_model_serializers/key_transform_test.rb +0 -263
  133. data/test/active_model_serializers/logging_test.rb +0 -77
  134. data/test/active_model_serializers/model_test.rb +0 -9
  135. data/test/active_model_serializers/railtie_test_isolated.rb +0 -63
  136. data/test/active_model_serializers/serialization_context_test_isolated.rb +0 -58
  137. data/test/active_model_serializers/test/schema_test.rb +0 -130
  138. data/test/active_model_serializers/test/serializer_test.rb +0 -62
  139. data/test/active_record_test.rb +0 -9
  140. data/test/adapter/deprecation_test.rb +0 -100
  141. data/test/adapter/json/belongs_to_test.rb +0 -45
  142. data/test/adapter/json/collection_test.rb +0 -90
  143. data/test/adapter/json/has_many_test.rb +0 -45
  144. data/test/adapter/json/transform_test.rb +0 -93
  145. data/test/adapter/json_api/belongs_to_test.rb +0 -155
  146. data/test/adapter/json_api/collection_test.rb +0 -95
  147. data/test/adapter/json_api/errors_test.rb +0 -78
  148. data/test/adapter/json_api/fields_test.rb +0 -87
  149. data/test/adapter/json_api/has_many_embed_ids_test.rb +0 -43
  150. data/test/adapter/json_api/has_many_explicit_serializer_test.rb +0 -96
  151. data/test/adapter/json_api/has_many_test.rb +0 -144
  152. data/test/adapter/json_api/has_one_test.rb +0 -80
  153. data/test/adapter/json_api/json_api_test.rb +0 -35
  154. data/test/adapter/json_api/linked_test.rb +0 -392
  155. data/test/adapter/json_api/links_test.rb +0 -93
  156. data/test/adapter/json_api/pagination_links_test.rb +0 -166
  157. data/test/adapter/json_api/parse_test.rb +0 -137
  158. data/test/adapter/json_api/relationship_test.rb +0 -161
  159. data/test/adapter/json_api/relationships_test.rb +0 -199
  160. data/test/adapter/json_api/resource_identifier_test.rb +0 -85
  161. data/test/adapter/json_api/resource_meta_test.rb +0 -100
  162. data/test/adapter/json_api/toplevel_jsonapi_test.rb +0 -82
  163. data/test/adapter/json_api/transform_test.rb +0 -502
  164. data/test/adapter/json_api/type_test.rb +0 -61
  165. data/test/adapter/json_test.rb +0 -45
  166. data/test/adapter/null_test.rb +0 -23
  167. data/test/adapter/polymorphic_test.rb +0 -171
  168. data/test/adapter_test.rb +0 -67
  169. data/test/array_serializer_test.rb +0 -22
  170. data/test/benchmark/app.rb +0 -65
  171. data/test/benchmark/benchmarking_support.rb +0 -67
  172. data/test/benchmark/bm_caching.rb +0 -119
  173. data/test/benchmark/bm_transform.rb +0 -34
  174. data/test/benchmark/config.ru +0 -3
  175. data/test/benchmark/controllers.rb +0 -84
  176. data/test/benchmark/fixtures.rb +0 -219
  177. data/test/cache_test.rb +0 -485
  178. data/test/collection_serializer_test.rb +0 -110
  179. data/test/fixtures/active_record.rb +0 -78
  180. data/test/fixtures/poro.rb +0 -282
  181. data/test/generators/scaffold_controller_generator_test.rb +0 -24
  182. data/test/generators/serializer_generator_test.rb +0 -57
  183. data/test/grape_test.rb +0 -82
  184. data/test/include_tree/from_include_args_test.rb +0 -26
  185. data/test/include_tree/from_string_test.rb +0 -94
  186. data/test/include_tree/include_args_to_hash_test.rb +0 -64
  187. data/test/lint_test.rb +0 -49
  188. data/test/logger_test.rb +0 -18
  189. data/test/poro_test.rb +0 -9
  190. data/test/serializable_resource_test.rb +0 -83
  191. data/test/serializers/association_macros_test.rb +0 -36
  192. data/test/serializers/associations_test.rb +0 -295
  193. data/test/serializers/attribute_test.rb +0 -151
  194. data/test/serializers/attributes_test.rb +0 -52
  195. data/test/serializers/caching_configuration_test_isolated.rb +0 -170
  196. data/test/serializers/configuration_test.rb +0 -32
  197. data/test/serializers/fieldset_test.rb +0 -14
  198. data/test/serializers/meta_test.rb +0 -196
  199. data/test/serializers/options_test.rb +0 -21
  200. data/test/serializers/read_attribute_for_serialization_test.rb +0 -79
  201. data/test/serializers/root_test.rb +0 -21
  202. data/test/serializers/serialization_test.rb +0 -55
  203. data/test/serializers/serializer_for_test.rb +0 -134
  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 -79
  206. data/test/support/rails5_shims.rb +0 -47
  207. data/test/support/rails_app.rb +0 -45
  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 -53
  215. data/test/test_helper.rb +0 -57
@@ -1,219 +0,0 @@
1
- Rails.configuration.serializers = []
2
- class AuthorSerializer < ActiveModel::Serializer
3
- attributes :id, :first_name, :last_name
4
-
5
- has_many :posts, embed: :ids
6
- has_one :bio
7
- end
8
- Rails.configuration.serializers << AuthorSerializer
9
-
10
- class BlogSerializer < ActiveModel::Serializer
11
- attributes :id, :name
12
- end
13
- Rails.configuration.serializers << BlogSerializer
14
-
15
- class CommentSerializer < ActiveModel::Serializer
16
- attributes :id, :body, :updated_at
17
-
18
- belongs_to :post
19
- belongs_to :author
20
- end
21
- Rails.configuration.serializers << CommentSerializer
22
-
23
- class PostSerializer < ActiveModel::Serializer
24
- attributes :id, :title, :body
25
-
26
- has_many :comments, serializer: CommentSerializer
27
- belongs_to :blog, serializer: BlogSerializer
28
- belongs_to :author, serializer: AuthorSerializer
29
-
30
- link(:post_authors) { 'https://example.com/post_authors' }
31
-
32
- meta do
33
- {
34
- rating: 5,
35
- favorite_count: 10
36
- }
37
- end
38
-
39
- def blog
40
- Blog.new(id: 999, name: 'Custom blog')
41
- end
42
- end
43
- Rails.configuration.serializers << PostSerializer
44
-
45
- class CachingAuthorSerializer < AuthorSerializer
46
- cache key: 'writer', skip_digest: true
47
- end
48
- Rails.configuration.serializers << CachingAuthorSerializer
49
-
50
- class CachingCommentSerializer < CommentSerializer
51
- cache expires_in: 1.day, skip_digest: true
52
- end
53
- Rails.configuration.serializers << CachingCommentSerializer
54
-
55
- # see https://github.com/rails-api/active_model_serializers/pull/1690/commits/68715b8f99bc29677e8a47bb3f305f23c077024b#r60344532
56
- class CachingPostSerializer < ActiveModel::Serializer
57
- cache key: 'post', expires_in: 0.1, skip_digest: true
58
-
59
- attributes :id, :title, :body
60
-
61
- belongs_to :blog, serializer: BlogSerializer
62
- belongs_to :author, serializer: CachingAuthorSerializer
63
- has_many :comments, serializer: CachingCommentSerializer
64
-
65
- link(:post_authors) { 'https://example.com/post_authors' }
66
-
67
- meta do
68
- {
69
- rating: 5,
70
- favorite_count: 10
71
- }
72
- end
73
-
74
- def blog
75
- Blog.new(id: 999, name: 'Custom blog')
76
- end
77
- end
78
- Rails.configuration.serializers << CachingPostSerializer
79
-
80
- class FragmentCachingAuthorSerializer < AuthorSerializer
81
- cache key: 'writer', only: [:first_name, :last_name], skip_digest: true
82
- end
83
- Rails.configuration.serializers << FragmentCachingAuthorSerializer
84
-
85
- class FragmentCachingCommentSerializer < CommentSerializer
86
- cache expires_in: 1.day, except: [:updated_at], skip_digest: true
87
- end
88
- Rails.configuration.serializers << CachingCommentSerializer
89
-
90
- # see https://github.com/rails-api/active_model_serializers/pull/1690/commits/68715b8f99bc29677e8a47bb3f305f23c077024b#r60344532
91
- class FragmentCachingPostSerializer < ActiveModel::Serializer
92
- cache key: 'post', expires_in: 0.1, skip_digest: true
93
-
94
- attributes :id, :title, :body
95
-
96
- belongs_to :blog, serializer: BlogSerializer
97
- belongs_to :author, serializer: FragmentCachingAuthorSerializer
98
- has_many :comments, serializer: FragmentCachingCommentSerializer
99
-
100
- link(:post_authors) { 'https://example.com/post_authors' }
101
-
102
- meta do
103
- {
104
- rating: 5,
105
- favorite_count: 10
106
- }
107
- end
108
-
109
- def blog
110
- Blog.new(id: 999, name: 'Custom blog')
111
- end
112
- end
113
- Rails.configuration.serializers << FragmentCachingPostSerializer
114
-
115
- if ENV['ENABLE_ACTIVE_RECORD'] == 'true'
116
- require 'active_record'
117
-
118
- ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
119
- ActiveRecord::Schema.define do
120
- self.verbose = false
121
-
122
- create_table :blogs, force: true do |t|
123
- t.string :name
124
- t.timestamps null: false
125
- end
126
- create_table :authors, force: true do |t|
127
- t.string :first_name
128
- t.string :last_name
129
- t.timestamps null: false
130
- end
131
- create_table :posts, force: true do |t|
132
- t.string :title
133
- t.text :body
134
- t.references :author
135
- t.references :blog
136
- t.timestamps null: false
137
- end
138
- create_table :comments, force: true do |t|
139
- t.text :body
140
- t.references :author
141
- t.references :post
142
- t.timestamps null: false
143
- end
144
- end
145
-
146
- class Comment < ActiveRecord::Base
147
- belongs_to :author
148
- belongs_to :post
149
- end
150
-
151
- class Author < ActiveRecord::Base
152
- has_many :posts
153
- has_many :comments
154
- end
155
-
156
- class Post < ActiveRecord::Base
157
- has_many :comments
158
- belongs_to :author
159
- belongs_to :blog
160
- end
161
-
162
- class Blog < ActiveRecord::Base
163
- has_many :posts
164
- end
165
- else
166
- # ActiveModelSerializers::Model is a convenient
167
- # serializable class to inherit from when making
168
- # serializable non-activerecord objects.
169
- class BenchmarkModel
170
- include ActiveModel::Model
171
- include ActiveModel::Serializers::JSON
172
-
173
- attr_reader :attributes
174
-
175
- def initialize(attributes = {})
176
- @attributes = attributes
177
- super
178
- end
179
-
180
- # Defaults to the downcased model name.
181
- def id
182
- attributes.fetch(:id) { self.class.name.downcase }
183
- end
184
-
185
- # Defaults to the downcased model name and updated_at
186
- def cache_key
187
- attributes.fetch(:cache_key) { "#{self.class.name.downcase}/#{id}" }
188
- end
189
-
190
- # Defaults to the time the serializer file was modified.
191
- def updated_at
192
- @updated_at ||= attributes.fetch(:updated_at) { File.mtime(__FILE__) }
193
- end
194
-
195
- def read_attribute_for_serialization(key)
196
- if key == :id || key == 'id'
197
- attributes.fetch(key) { id }
198
- else
199
- attributes[key]
200
- end
201
- end
202
- end
203
-
204
- class Comment < BenchmarkModel
205
- attr_accessor :id, :body, :updated_at
206
- end
207
-
208
- class Author < BenchmarkModel
209
- attr_accessor :id, :first_name, :last_name, :posts
210
- end
211
-
212
- class Post < BenchmarkModel
213
- attr_accessor :id, :title, :body, :comments, :blog, :author
214
- end
215
-
216
- class Blog < BenchmarkModel
217
- attr_accessor :id, :name
218
- end
219
- end
data/test/cache_test.rb DELETED
@@ -1,485 +0,0 @@
1
- require 'test_helper'
2
- require 'tmpdir'
3
- require 'tempfile'
4
-
5
- module ActiveModelSerializers
6
- class CacheTest < ActiveSupport::TestCase
7
- UncachedAuthor = Class.new(Author) do
8
- # To confirm cache_key is set using updated_at and cache_key option passed to cache
9
- undef_method :cache_key
10
- end
11
-
12
- Article = Class.new(::Model) do
13
- # To confirm error is raised when cache_key is not set and cache_key option not passed to cache
14
- undef_method :cache_key
15
- end
16
-
17
- ArticleSerializer = Class.new(ActiveModel::Serializer) do
18
- cache only: [:place], skip_digest: true
19
- attributes :title
20
- end
21
-
22
- InheritedRoleSerializer = Class.new(RoleSerializer) do
23
- cache key: 'inherited_role', only: [:name, :special_attribute]
24
- attribute :special_attribute
25
- end
26
-
27
- setup do
28
- cache_store.clear
29
- @comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
30
- @post = Post.new(title: 'New Post', body: 'Body')
31
- @bio = Bio.new(id: 1, content: 'AMS Contributor')
32
- @author = Author.new(name: 'Joao M. D. Moura')
33
- @blog = Blog.new(id: 999, name: 'Custom blog', writer: @author, articles: [])
34
- @role = Role.new(name: 'Great Author')
35
- @location = Location.new(lat: '-23.550520', lng: '-46.633309')
36
- @place = Place.new(name: 'Amazing Place')
37
- @author.posts = [@post]
38
- @author.roles = [@role]
39
- @role.author = @author
40
- @author.bio = @bio
41
- @bio.author = @author
42
- @post.comments = [@comment]
43
- @post.author = @author
44
- @comment.post = @post
45
- @comment.author = @author
46
- @post.blog = @blog
47
- @location.place = @place
48
-
49
- @location_serializer = LocationSerializer.new(@location)
50
- @bio_serializer = BioSerializer.new(@bio)
51
- @role_serializer = RoleSerializer.new(@role)
52
- @post_serializer = PostSerializer.new(@post)
53
- @author_serializer = AuthorSerializer.new(@author)
54
- @comment_serializer = CommentSerializer.new(@comment)
55
- @blog_serializer = BlogSerializer.new(@blog)
56
- end
57
-
58
- def test_explicit_cache_store
59
- default_store = Class.new(ActiveModel::Serializer) do
60
- cache
61
- end
62
- explicit_store = Class.new(ActiveModel::Serializer) do
63
- cache cache_store: ActiveSupport::Cache::FileStore
64
- end
65
-
66
- assert ActiveSupport::Cache::MemoryStore, ActiveModelSerializers.config.cache_store
67
- assert ActiveSupport::Cache::MemoryStore, default_store.cache_store
68
- assert ActiveSupport::Cache::FileStore, explicit_store.cache_store
69
- end
70
-
71
- def test_inherited_cache_configuration
72
- inherited_serializer = Class.new(PostSerializer)
73
-
74
- assert_equal PostSerializer._cache_key, inherited_serializer._cache_key
75
- assert_equal PostSerializer._cache_options, inherited_serializer._cache_options
76
- end
77
-
78
- def test_override_cache_configuration
79
- inherited_serializer = Class.new(PostSerializer) do
80
- cache key: 'new-key'
81
- end
82
-
83
- assert_equal PostSerializer._cache_key, 'post'
84
- assert_equal inherited_serializer._cache_key, 'new-key'
85
- end
86
-
87
- def test_cache_definition
88
- assert_equal(cache_store, @post_serializer.class._cache)
89
- assert_equal(cache_store, @author_serializer.class._cache)
90
- assert_equal(cache_store, @comment_serializer.class._cache)
91
- end
92
-
93
- def test_cache_key_definition
94
- assert_equal('post', @post_serializer.class._cache_key)
95
- assert_equal('writer', @author_serializer.class._cache_key)
96
- assert_equal(nil, @comment_serializer.class._cache_key)
97
- end
98
-
99
- def test_cache_key_interpolation_with_updated_at_when_cache_key_is_not_defined_on_object
100
- uncached_author = UncachedAuthor.new(name: 'Joao M. D. Moura')
101
- uncached_author_serializer = AuthorSerializer.new(uncached_author)
102
-
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}"
106
- assert_equal(uncached_author_serializer.attributes.to_json, cache_store.fetch(key).to_json)
107
- end
108
-
109
- def test_default_cache_key_fallback
110
- render_object_with_cache(@comment)
111
- key = "#{@comment.cache_key}/#{adapter.cached_name}"
112
- assert_equal(@comment_serializer.attributes.to_json, cache_store.fetch(key).to_json)
113
- end
114
-
115
- def test_error_is_raised_if_cache_key_is_not_defined_on_object_or_passed_as_cache_option
116
- article = Article.new(title: 'Must Read')
117
- e = assert_raises ActiveModel::Serializer::UndefinedCacheKey do
118
- render_object_with_cache(article)
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)
121
- end
122
-
123
- def test_cache_options_definition
124
- assert_equal({ expires_in: 0.1, skip_digest: true }, @post_serializer.class._cache_options)
125
- assert_equal(nil, @blog_serializer.class._cache_options)
126
- assert_equal({ expires_in: 1.day, skip_digest: true }, @comment_serializer.class._cache_options)
127
- end
128
-
129
- def test_fragment_cache_definition
130
- assert_equal([:name], @role_serializer.class._cache_only)
131
- assert_equal([:content], @bio_serializer.class._cache_except)
132
- end
133
-
134
- def test_associations_separately_cache
135
- cache_store.clear
136
- assert_equal(nil, cache_store.fetch(@post.cache_key))
137
- assert_equal(nil, cache_store.fetch(@comment.cache_key))
138
-
139
- Timecop.freeze(Time.current) do
140
- render_object_with_cache(@post)
141
-
142
- key = "#{@post.cache_key}/#{adapter.cached_name}"
143
- assert_equal(@post_serializer.attributes, cache_store.fetch(key))
144
- key = "#{@comment.cache_key}/#{adapter.cached_name}"
145
- assert_equal(@comment_serializer.attributes, cache_store.fetch(key))
146
- end
147
- end
148
-
149
- def test_associations_cache_when_updated
150
- Timecop.freeze(Time.current) do
151
- # Generate a new Cache of Post object and each objects related to it.
152
- render_object_with_cache(@post)
153
-
154
- # Check if it cached the objects separately
155
- key = "#{@post.cache_key}/#{adapter.cached_name}"
156
- assert_equal(@post_serializer.attributes, cache_store.fetch(key))
157
- key = "#{@comment.cache_key}/#{adapter.cached_name}"
158
- assert_equal(@comment_serializer.attributes, cache_store.fetch(key))
159
-
160
- # Simulating update on comments relationship with Post
161
- new_comment = Comment.new(id: 2567, body: 'ZOMG A NEW COMMENT')
162
- new_comment_serializer = CommentSerializer.new(new_comment)
163
- @post.comments = [new_comment]
164
-
165
- # Ask for the serialized object
166
- render_object_with_cache(@post)
167
-
168
- # Check if the the new comment was cached
169
- key = "#{new_comment.cache_key}/#{adapter.cached_name}"
170
- assert_equal(new_comment_serializer.attributes, cache_store.fetch(key))
171
- key = "#{@post.cache_key}/#{adapter.cached_name}"
172
- assert_equal(@post_serializer.attributes, cache_store.fetch(key))
173
- end
174
- end
175
-
176
- def test_fragment_fetch_with_virtual_associations
177
- expected_result = {
178
- id: @location.id,
179
- lat: @location.lat,
180
- lng: @location.lng,
181
- place: 'Nowhere'
182
- }
183
-
184
- hash = render_object_with_cache(@location)
185
-
186
- assert_equal(hash, expected_result)
187
- key = "#{@location.cache_key}/#{adapter.cached_name}"
188
- assert_equal({ place: 'Nowhere' }, cache_store.fetch(key))
189
- end
190
-
191
- def test_fragment_cache_with_inheritance
192
- inherited = render_object_with_cache(@role, serializer: InheritedRoleSerializer)
193
- base = render_object_with_cache(@role)
194
-
195
- assert_includes(inherited.keys, :special_attribute)
196
- refute_includes(base.keys, :special_attribute)
197
- end
198
-
199
- def test_uses_adapter_in_cache_key
200
- render_object_with_cache(@post)
201
- key = "#{@post.cache_key}/#{adapter.class.to_s.demodulize.underscore}"
202
- assert_equal(@post_serializer.attributes, cache_store.fetch(key))
203
- end
204
-
205
- # Based on original failing test by @kevintyll
206
- # rubocop:disable Metrics/AbcSize
207
- def test_a_serializer_rendered_by_two_adapter_returns_differently_cached_attributes
208
- Object.const_set(:Alert, Class.new(ActiveModelSerializers::Model) do
209
- attr_accessor :id, :status, :resource, :started_at, :ended_at, :updated_at, :created_at
210
- end)
211
- Object.const_set(:UncachedAlertSerializer, Class.new(ActiveModel::Serializer) do
212
- attributes :id, :status, :resource, :started_at, :ended_at, :updated_at, :created_at
213
- end)
214
- Object.const_set(:AlertSerializer, Class.new(UncachedAlertSerializer) do
215
- cache
216
- end)
217
-
218
- alert = Alert.new(
219
- id: 1,
220
- status: 'fail',
221
- resource: 'resource-1',
222
- started_at: Time.new(2016, 3, 31, 21, 36, 35, 0),
223
- ended_at: nil,
224
- updated_at: Time.new(2016, 3, 31, 21, 27, 35, 0),
225
- created_at: Time.new(2016, 3, 31, 21, 37, 35, 0)
226
- )
227
-
228
- expected_cached_attributes = {
229
- id: 1,
230
- status: 'fail',
231
- resource: 'resource-1',
232
- started_at: alert.started_at,
233
- ended_at: nil,
234
- updated_at: alert.updated_at,
235
- created_at: alert.created_at
236
- }
237
- expected_cached_jsonapi_attributes = {
238
- id: '1',
239
- type: 'alerts',
240
- attributes: {
241
- status: 'fail',
242
- resource: 'resource-1',
243
- started_at: alert.started_at,
244
- ended_at: nil,
245
- updated_at: alert.updated_at,
246
- created_at: alert.created_at
247
- }
248
- }
249
-
250
- # Assert attributes are serialized correctly
251
- serializable_alert = serializable(alert, serializer: AlertSerializer, adapter: :attributes)
252
- attributes_serialization = serializable_alert.as_json
253
- assert_equal expected_cached_attributes, alert.attributes
254
- assert_equal alert.attributes, attributes_serialization
255
- attributes_cache_key = serializable_alert.adapter.serializer.cache_key(serializable_alert.adapter)
256
- assert_equal attributes_serialization, cache_store.fetch(attributes_cache_key)
257
-
258
- serializable_alert = serializable(alert, serializer: AlertSerializer, adapter: :json_api)
259
- jsonapi_cache_key = serializable_alert.adapter.serializer.cache_key(serializable_alert.adapter)
260
- # Assert cache keys differ
261
- refute_equal attributes_cache_key, jsonapi_cache_key
262
- # Assert (cached) serializations differ
263
- jsonapi_serialization = serializable_alert.as_json
264
- assert_equal alert.status, jsonapi_serialization.fetch(:data).fetch(:attributes).fetch(:status)
265
- serializable_alert = serializable(alert, serializer: UncachedAlertSerializer, adapter: :json_api)
266
- assert_equal serializable_alert.as_json, jsonapi_serialization
267
-
268
- cached_serialization = cache_store.fetch(jsonapi_cache_key)
269
- assert_equal expected_cached_jsonapi_attributes, cached_serialization
270
- ensure
271
- Object.send(:remove_const, :Alert)
272
- Object.send(:remove_const, :AlertSerializer)
273
- Object.send(:remove_const, :UncachedAlertSerializer)
274
- end
275
- # rubocop:enable Metrics/AbcSize
276
-
277
- def test_uses_file_digest_in_cache_key
278
- render_object_with_cache(@blog)
279
- key = "#{@blog.cache_key}/#{adapter.cached_name}/#{::Model::FILE_DIGEST}"
280
- assert_equal(@blog_serializer.attributes, cache_store.fetch(key))
281
- end
282
-
283
- def test_cache_digest_definition
284
- assert_equal(::Model::FILE_DIGEST, @post_serializer.class._cache_digest)
285
- end
286
-
287
- def test_object_cache_keys
288
- serializable = ActiveModelSerializers::SerializableResource.new([@comment, @comment])
289
- include_tree = ActiveModel::Serializer::IncludeTree.from_include_args('*')
290
-
291
- actual = ActiveModel::Serializer.object_cache_keys(serializable.adapter.serializer, serializable.adapter, include_tree)
292
-
293
- assert_equal 3, actual.size
294
- assert actual.any? { |key| key == "comment/1/#{serializable.adapter.cached_name}" }
295
- assert actual.any? { |key| key =~ %r{post/post-\d+} }
296
- assert actual.any? { |key| key =~ %r{author/author-\d+} }
297
- end
298
-
299
- def test_cached_attributes
300
- serializer = ActiveModel::Serializer::CollectionSerializer.new([@comment, @comment])
301
-
302
- Timecop.freeze(Time.current) do
303
- render_object_with_cache(@comment)
304
-
305
- attributes = Adapter::Attributes.new(serializer)
306
- attributes.send(:cache_attributes)
307
- cached_attributes = attributes.instance_variable_get(:@cached_attributes)
308
-
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
-
312
- writer = @comment.post.blog.writer
313
- writer_cache_key = writer.cache_key
314
-
315
- assert_equal cached_attributes["#{writer_cache_key}/#{attributes.cached_name}"], Author.new(id: 'author', name: 'Joao M. D. Moura').attributes
316
- end
317
- end
318
-
319
- def test_serializer_file_path_on_nix
320
- path = '/Users/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb'
321
- caller_line = "#{path}:1:in `<top (required)>'"
322
- assert_equal caller_line[ActiveModel::Serializer::CALLER_FILE], path
323
- end
324
-
325
- def test_serializer_file_path_on_windows
326
- path = 'c:/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb'
327
- caller_line = "#{path}:1:in `<top (required)>'"
328
- assert_equal caller_line[ActiveModel::Serializer::CALLER_FILE], path
329
- end
330
-
331
- def test_serializer_file_path_with_space
332
- path = '/Users/git/ember js/ember-crm-backend/app/serializers/lead_serializer.rb'
333
- caller_line = "#{path}:1:in `<top (required)>'"
334
- assert_equal caller_line[ActiveModel::Serializer::CALLER_FILE], path
335
- end
336
-
337
- def test_serializer_file_path_with_submatch
338
- # The submatch in the path ensures we're using a correctly greedy regexp.
339
- path = '/Users/git/ember js/ember:123:in x/app/serializers/lead_serializer.rb'
340
- caller_line = "#{path}:1:in `<top (required)>'"
341
- assert_equal caller_line[ActiveModel::Serializer::CALLER_FILE], path
342
- end
343
-
344
- def test_digest_caller_file
345
- contents = "puts 'AMS rocks'!"
346
- dir = Dir.mktmpdir('space char')
347
- file = Tempfile.new('some_ruby.rb', dir)
348
- file.write(contents)
349
- path = file.path
350
- caller_line = "#{path}:1:in `<top (required)>'"
351
- file.close
352
- assert_equal ActiveModel::Serializer.digest_caller_file(caller_line), Digest::MD5.hexdigest(contents)
353
- ensure
354
- file.unlink
355
- FileUtils.remove_entry dir
356
- end
357
-
358
- def test_warn_on_serializer_not_defined_in_file
359
- called = false
360
- serializer = Class.new(ActiveModel::Serializer)
361
- assert_output(nil, /_cache_digest/) do
362
- serializer.digest_caller_file('')
363
- called = true
364
- end
365
- assert called
366
- end
367
-
368
- def test_cached_false_without_cache_store
369
- cached_serializer = build_cached_serializer do |serializer|
370
- serializer._cache = nil
371
- end
372
- refute cached_serializer.class.cache_enabled?
373
- end
374
-
375
- def test_cached_true_with_cache_store_and_without_cache_only_and_cache_except
376
- cached_serializer = build_cached_serializer do |serializer|
377
- serializer._cache = Object
378
- end
379
- assert cached_serializer.class.cache_enabled?
380
- end
381
-
382
- def test_cached_false_with_cache_store_and_with_cache_only
383
- cached_serializer = build_cached_serializer do |serializer|
384
- serializer._cache = Object
385
- serializer._cache_only = [:name]
386
- end
387
- refute cached_serializer.class.cache_enabled?
388
- end
389
-
390
- def test_cached_false_with_cache_store_and_with_cache_except
391
- cached_serializer = build_cached_serializer do |serializer|
392
- serializer._cache = Object
393
- serializer._cache_except = [:content]
394
- end
395
- refute cached_serializer.class.cache_enabled?
396
- end
397
-
398
- def test_fragment_cached_false_without_cache_store
399
- cached_serializer = build_cached_serializer do |serializer|
400
- serializer._cache = nil
401
- serializer._cache_only = [:name]
402
- end
403
- refute cached_serializer.class.fragment_cache_enabled?
404
- end
405
-
406
- def test_fragment_cached_true_with_cache_store_and_cache_only
407
- cached_serializer = build_cached_serializer do |serializer|
408
- serializer._cache = Object
409
- serializer._cache_only = [:name]
410
- end
411
- assert cached_serializer.class.fragment_cache_enabled?
412
- end
413
-
414
- def test_fragment_cached_true_with_cache_store_and_cache_except
415
- cached_serializer = build_cached_serializer do |serializer|
416
- serializer._cache = Object
417
- serializer._cache_except = [:content]
418
- end
419
- assert cached_serializer.class.fragment_cache_enabled?
420
- end
421
-
422
- def test_fragment_cached_false_with_cache_store_and_cache_except_and_cache_only
423
- cached_serializer = build_cached_serializer do |serializer|
424
- serializer._cache = Object
425
- serializer._cache_except = [:content]
426
- serializer._cache_only = [:name]
427
- end
428
- refute cached_serializer.class.fragment_cache_enabled?
429
- end
430
-
431
- 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))
437
-
438
- expected_result = {
439
- id: @role.id,
440
- description: @role.description,
441
- slug: "#{@role.name}-#{@role.id}",
442
- name: @role.name
443
- }
444
- assert_equal(@role_hash, expected_result)
445
- end
446
-
447
- def test_fragment_fetch_with_namespaced_object
448
- @spam = Spam::UnrelatedLink.new(id: 'spam-id-1')
449
- @spam_serializer = Spam::UnrelatedLinkSerializer.new(@spam)
450
- @spam_hash = @spam_serializer.fetch_fragment_cache(ActiveModelSerializers::Adapter.configured_adapter.new(@spam_serializer))
451
- expected_result = {
452
- id: @spam.id
453
- }
454
- assert_equal(@spam_hash, expected_result)
455
- end
456
-
457
- private
458
-
459
- def cache_store
460
- ActiveModelSerializers.config.cache_store
461
- end
462
-
463
- def build_cached_serializer
464
- serializer = Class.new(ActiveModel::Serializer)
465
- serializer._cache_key = nil
466
- serializer._cache_options = nil
467
- yield serializer if block_given?
468
- serializer.new(Object)
469
- end
470
-
471
- def render_object_with_cache(obj, options = {})
472
- @serializable_resource = serializable(obj, options)
473
- @serializable_resource.serializable_hash
474
- end
475
-
476
- def adapter
477
- @serializable_resource.adapter
478
- end
479
-
480
- def cached_serialization(serializer)
481
- cache_key = serializer.cache_key(adapter)
482
- cache_store.fetch(cache_key)
483
- end
484
- end
485
- end