active_model_serializers 0.10.0 → 0.10.7
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.
- checksums.yaml +5 -5
- data/.rubocop.yml +6 -5
- data/.travis.yml +30 -21
- data/CHANGELOG.md +172 -2
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +23 -4
- data/README.md +166 -28
- data/Rakefile +3 -32
- data/active_model_serializers.gemspec +22 -25
- data/appveyor.yml +10 -6
- data/bin/rubocop +38 -0
- data/docs/README.md +2 -1
- data/docs/general/adapters.md +35 -11
- data/docs/general/caching.md +7 -1
- data/docs/general/configuration_options.md +86 -1
- data/docs/general/deserialization.md +1 -1
- data/docs/general/fields.md +31 -0
- data/docs/general/getting_started.md +1 -1
- data/docs/general/logging.md +7 -0
- data/docs/general/rendering.md +63 -25
- data/docs/general/serializers.md +125 -14
- data/docs/howto/add_pagination_links.md +16 -17
- data/docs/howto/add_relationship_links.md +140 -0
- data/docs/howto/add_root_key.md +11 -0
- data/docs/howto/grape_integration.md +42 -0
- data/docs/howto/outside_controller_use.md +12 -4
- data/docs/howto/passing_arbitrary_options.md +2 -2
- data/docs/howto/serialize_poro.md +46 -5
- data/docs/howto/test.md +2 -0
- data/docs/howto/upgrade_from_0_8_to_0_10.md +265 -0
- data/docs/integrations/ember-and-json-api.md +67 -32
- data/docs/jsonapi/schema.md +1 -1
- data/lib/action_controller/serialization.rb +13 -3
- data/lib/active_model/serializer/adapter/base.rb +2 -0
- data/lib/active_model/serializer/array_serializer.rb +8 -5
- data/lib/active_model/serializer/association.rb +62 -10
- data/lib/active_model/serializer/belongs_to_reflection.rb +4 -3
- data/lib/active_model/serializer/collection_serializer.rb +39 -13
- data/lib/active_model/serializer/{caching.rb → concerns/caching.rb} +82 -115
- data/lib/active_model/serializer/error_serializer.rb +11 -7
- data/lib/active_model/serializer/errors_serializer.rb +25 -20
- data/lib/active_model/serializer/has_many_reflection.rb +3 -3
- data/lib/active_model/serializer/has_one_reflection.rb +1 -4
- data/lib/active_model/serializer/lazy_association.rb +95 -0
- data/lib/active_model/serializer/lint.rb +134 -130
- data/lib/active_model/serializer/reflection.rb +127 -67
- data/lib/active_model/serializer/version.rb +1 -1
- data/lib/active_model/serializer.rb +297 -79
- data/lib/active_model_serializers/adapter/attributes.rb +3 -66
- data/lib/active_model_serializers/adapter/base.rb +39 -39
- data/lib/active_model_serializers/adapter/json_api/deserialization.rb +2 -2
- data/lib/active_model_serializers/adapter/json_api/link.rb +1 -1
- data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +47 -21
- data/lib/active_model_serializers/adapter/json_api/relationship.rb +75 -23
- data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +39 -10
- data/lib/active_model_serializers/adapter/json_api.rb +71 -57
- data/lib/active_model_serializers/adapter.rb +6 -0
- data/lib/active_model_serializers/deprecate.rb +1 -2
- data/lib/active_model_serializers/deserialization.rb +2 -0
- data/lib/active_model_serializers/lookup_chain.rb +80 -0
- data/lib/active_model_serializers/model.rb +109 -28
- data/lib/active_model_serializers/railtie.rb +3 -1
- data/lib/active_model_serializers/register_jsonapi_renderer.rb +44 -31
- data/lib/active_model_serializers/serializable_resource.rb +6 -5
- data/lib/active_model_serializers/serialization_context.rb +10 -3
- data/lib/active_model_serializers/test/schema.rb +2 -2
- data/lib/active_model_serializers.rb +16 -1
- data/lib/generators/rails/resource_override.rb +1 -1
- data/lib/generators/rails/serializer_generator.rb +4 -4
- data/lib/grape/active_model_serializers.rb +7 -5
- data/lib/grape/formatters/active_model_serializers.rb +19 -2
- data/lib/grape/helpers/active_model_serializers.rb +1 -0
- data/lib/tasks/rubocop.rake +53 -0
- data/test/action_controller/adapter_selector_test.rb +14 -5
- data/test/action_controller/explicit_serializer_test.rb +5 -4
- data/test/action_controller/json/include_test.rb +106 -27
- data/test/action_controller/json_api/deserialization_test.rb +1 -1
- data/test/action_controller/json_api/errors_test.rb +8 -9
- data/test/action_controller/json_api/fields_test.rb +66 -0
- data/test/action_controller/json_api/linked_test.rb +29 -24
- data/test/action_controller/json_api/pagination_test.rb +31 -23
- data/test/action_controller/json_api/transform_test.rb +11 -3
- data/test/action_controller/lookup_proc_test.rb +49 -0
- data/test/action_controller/namespace_lookup_test.rb +232 -0
- data/test/action_controller/serialization_scope_name_test.rb +12 -6
- data/test/action_controller/serialization_test.rb +12 -9
- data/test/active_model_serializers/json_pointer_test.rb +15 -13
- data/test/active_model_serializers/model_test.rb +137 -4
- data/test/active_model_serializers/railtie_test_isolated.rb +12 -7
- data/test/active_model_serializers/register_jsonapi_renderer_test_isolated.rb +161 -0
- data/test/active_model_serializers/serialization_context_test_isolated.rb +23 -10
- data/test/active_model_serializers/test/schema_test.rb +3 -2
- data/test/adapter/attributes_test.rb +40 -0
- data/test/adapter/json/collection_test.rb +14 -0
- data/test/adapter/json/has_many_test.rb +10 -2
- data/test/adapter/json/transform_test.rb +15 -15
- data/test/adapter/json_api/collection_test.rb +4 -3
- data/test/adapter/json_api/errors_test.rb +17 -19
- data/test/adapter/json_api/fields_test.rb +12 -3
- data/test/adapter/json_api/has_many_test.rb +49 -20
- data/test/adapter/json_api/include_data_if_sideloaded_test.rb +213 -0
- data/test/adapter/json_api/json_api_test.rb +5 -7
- data/test/adapter/json_api/linked_test.rb +33 -12
- data/test/adapter/json_api/links_test.rb +4 -2
- data/test/adapter/json_api/pagination_links_test.rb +53 -13
- data/test/adapter/json_api/parse_test.rb +1 -1
- data/test/adapter/json_api/relationship_test.rb +309 -73
- data/test/adapter/json_api/resource_meta_test.rb +3 -3
- data/test/adapter/json_api/transform_test.rb +263 -253
- data/test/adapter/json_api/type_test.rb +168 -36
- data/test/adapter/json_test.rb +8 -7
- data/test/adapter/null_test.rb +1 -2
- data/test/adapter/polymorphic_test.rb +52 -5
- data/test/adapter_test.rb +1 -1
- data/test/benchmark/app.rb +1 -1
- data/test/benchmark/benchmarking_support.rb +1 -1
- data/test/benchmark/bm_active_record.rb +81 -0
- data/test/benchmark/bm_adapter.rb +38 -0
- data/test/benchmark/bm_caching.rb +16 -16
- data/test/benchmark/bm_lookup_chain.rb +83 -0
- data/test/benchmark/bm_transform.rb +21 -10
- data/test/benchmark/controllers.rb +16 -17
- data/test/benchmark/fixtures.rb +72 -72
- data/test/cache_test.rb +235 -69
- data/test/collection_serializer_test.rb +31 -14
- data/test/fixtures/active_record.rb +45 -10
- data/test/fixtures/poro.rb +124 -181
- data/test/generators/serializer_generator_test.rb +23 -5
- data/test/grape_test.rb +170 -56
- data/test/lint_test.rb +1 -1
- data/test/logger_test.rb +13 -11
- data/test/serializable_resource_test.rb +18 -22
- data/test/serializers/association_macros_test.rb +3 -2
- data/test/serializers/associations_test.rb +222 -49
- data/test/serializers/attribute_test.rb +5 -3
- data/test/serializers/attributes_test.rb +1 -1
- data/test/serializers/caching_configuration_test_isolated.rb +6 -6
- data/test/serializers/fieldset_test.rb +1 -1
- data/test/serializers/meta_test.rb +12 -6
- data/test/serializers/options_test.rb +17 -6
- data/test/serializers/read_attribute_for_serialization_test.rb +3 -3
- data/test/serializers/reflection_test.rb +427 -0
- data/test/serializers/root_test.rb +1 -1
- data/test/serializers/serialization_test.rb +2 -2
- data/test/serializers/serializer_for_test.rb +12 -10
- data/test/serializers/serializer_for_with_namespace_test.rb +88 -0
- data/test/support/isolated_unit.rb +9 -4
- data/test/support/rails5_shims.rb +8 -2
- data/test/support/rails_app.rb +2 -9
- data/test/support/serialization_testing.rb +31 -5
- data/test/test_helper.rb +13 -0
- metadata +130 -71
- data/.rubocop_todo.yml +0 -167
- data/docs/ARCHITECTURE.md +0 -126
- data/lib/active_model/serializer/associations.rb +0 -100
- data/lib/active_model/serializer/attributes.rb +0 -82
- data/lib/active_model/serializer/collection_reflection.rb +0 -7
- data/lib/active_model/serializer/configuration.rb +0 -35
- data/lib/active_model/serializer/include_tree.rb +0 -111
- data/lib/active_model/serializer/links.rb +0 -35
- data/lib/active_model/serializer/meta.rb +0 -29
- data/lib/active_model/serializer/singular_reflection.rb +0 -7
- data/lib/active_model/serializer/type.rb +0 -25
- data/lib/active_model_serializers/key_transform.rb +0 -70
- data/test/active_model_serializers/key_transform_test.rb +0 -263
- data/test/adapter/json_api/has_many_embed_ids_test.rb +0 -43
- data/test/adapter/json_api/relationships_test.rb +0 -199
- data/test/adapter/json_api/resource_identifier_test.rb +0 -85
- data/test/include_tree/from_include_args_test.rb +0 -26
- data/test/include_tree/from_string_test.rb +0 -94
- data/test/include_tree/include_args_to_hash_test.rb +0 -64
data/test/cache_test.rb
CHANGED
|
@@ -4,22 +4,111 @@ require 'tempfile'
|
|
|
4
4
|
|
|
5
5
|
module ActiveModelSerializers
|
|
6
6
|
class CacheTest < ActiveSupport::TestCase
|
|
7
|
-
|
|
8
|
-
|
|
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
|
|
9
10
|
undef_method :cache_key
|
|
10
11
|
end
|
|
12
|
+
class ArticleSerializer < ActiveModel::Serializer
|
|
13
|
+
cache only: [:place], skip_digest: true
|
|
14
|
+
attributes :title
|
|
15
|
+
end
|
|
11
16
|
|
|
12
|
-
|
|
13
|
-
|
|
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
|
|
14
46
|
undef_method :cache_key
|
|
15
47
|
end
|
|
48
|
+
class AuthorSerializer < ActiveModel::Serializer
|
|
49
|
+
cache key: 'writer', skip_digest: true
|
|
50
|
+
attributes :id, :name
|
|
16
51
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
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
|
|
20
82
|
end
|
|
21
83
|
|
|
22
|
-
|
|
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
|
|
23
112
|
cache key: 'inherited_role', only: [:name, :special_attribute]
|
|
24
113
|
attribute :special_attribute
|
|
25
114
|
end
|
|
@@ -27,10 +116,10 @@ module ActiveModelSerializers
|
|
|
27
116
|
setup do
|
|
28
117
|
cache_store.clear
|
|
29
118
|
@comment = Comment.new(id: 1, body: 'ZOMG A COMMENT')
|
|
30
|
-
@post = Post.new(title: 'New Post', body: 'Body')
|
|
119
|
+
@post = Post.new(id: 'post', title: 'New Post', body: 'Body')
|
|
31
120
|
@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
|
|
121
|
+
@author = Author.new(id: 'author', name: 'Joao M. D. Moura')
|
|
122
|
+
@blog = Blog.new(id: 999, name: 'Custom blog', writer: @author)
|
|
34
123
|
@role = Role.new(name: 'Great Author')
|
|
35
124
|
@location = Location.new(lat: '-23.550520', lng: '-46.633309')
|
|
36
125
|
@place = Place.new(name: 'Amazing Place')
|
|
@@ -93,7 +182,7 @@ module ActiveModelSerializers
|
|
|
93
182
|
def test_cache_key_definition
|
|
94
183
|
assert_equal('post', @post_serializer.class._cache_key)
|
|
95
184
|
assert_equal('writer', @author_serializer.class._cache_key)
|
|
96
|
-
|
|
185
|
+
assert_nil(@comment_serializer.class._cache_key)
|
|
97
186
|
end
|
|
98
187
|
|
|
99
188
|
def test_cache_key_interpolation_with_updated_at_when_cache_key_is_not_defined_on_object
|
|
@@ -101,14 +190,28 @@ module ActiveModelSerializers
|
|
|
101
190
|
uncached_author_serializer = AuthorSerializer.new(uncached_author)
|
|
102
191
|
|
|
103
192
|
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(
|
|
105
|
-
key = "#{key}/#{adapter.
|
|
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}"
|
|
106
195
|
assert_equal(uncached_author_serializer.attributes.to_json, cache_store.fetch(key).to_json)
|
|
107
196
|
end
|
|
108
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
|
+
|
|
109
212
|
def test_default_cache_key_fallback
|
|
110
213
|
render_object_with_cache(@comment)
|
|
111
|
-
key = "#{@comment.cache_key}/#{adapter.
|
|
214
|
+
key = "#{@comment.cache_key}/#{adapter.cache_key}"
|
|
112
215
|
assert_equal(@comment_serializer.attributes.to_json, cache_store.fetch(key).to_json)
|
|
113
216
|
end
|
|
114
217
|
|
|
@@ -117,31 +220,31 @@ module ActiveModelSerializers
|
|
|
117
220
|
e = assert_raises ActiveModel::Serializer::UndefinedCacheKey do
|
|
118
221
|
render_object_with_cache(article)
|
|
119
222
|
end
|
|
120
|
-
assert_match(/ActiveModelSerializers::CacheTest::Article must define #cache_key, or the 'key:' option must be passed into '
|
|
223
|
+
assert_match(/ActiveModelSerializers::CacheTest::Article must define #cache_key, or the 'key:' option must be passed into 'ActiveModelSerializers::CacheTest::ArticleSerializer.cache'/, e.message)
|
|
121
224
|
end
|
|
122
225
|
|
|
123
226
|
def test_cache_options_definition
|
|
124
227
|
assert_equal({ expires_in: 0.1, skip_digest: true }, @post_serializer.class._cache_options)
|
|
125
|
-
|
|
228
|
+
assert_nil(@blog_serializer.class._cache_options)
|
|
126
229
|
assert_equal({ expires_in: 1.day, skip_digest: true }, @comment_serializer.class._cache_options)
|
|
127
230
|
end
|
|
128
231
|
|
|
129
232
|
def test_fragment_cache_definition
|
|
130
|
-
assert_equal([:name], @role_serializer.class._cache_only)
|
|
233
|
+
assert_equal([:name, :slug], @role_serializer.class._cache_only)
|
|
131
234
|
assert_equal([:content], @bio_serializer.class._cache_except)
|
|
132
235
|
end
|
|
133
236
|
|
|
134
237
|
def test_associations_separately_cache
|
|
135
238
|
cache_store.clear
|
|
136
|
-
|
|
137
|
-
|
|
239
|
+
assert_nil(cache_store.fetch(@post.cache_key))
|
|
240
|
+
assert_nil(cache_store.fetch(@comment.cache_key))
|
|
138
241
|
|
|
139
242
|
Timecop.freeze(Time.current) do
|
|
140
243
|
render_object_with_cache(@post)
|
|
141
244
|
|
|
142
|
-
key = "#{@post.cache_key}/#{adapter.
|
|
245
|
+
key = "#{@post.cache_key}/#{adapter.cache_key}"
|
|
143
246
|
assert_equal(@post_serializer.attributes, cache_store.fetch(key))
|
|
144
|
-
key = "#{@comment.cache_key}/#{adapter.
|
|
247
|
+
key = "#{@comment.cache_key}/#{adapter.cache_key}"
|
|
145
248
|
assert_equal(@comment_serializer.attributes, cache_store.fetch(key))
|
|
146
249
|
end
|
|
147
250
|
end
|
|
@@ -152,9 +255,9 @@ module ActiveModelSerializers
|
|
|
152
255
|
render_object_with_cache(@post)
|
|
153
256
|
|
|
154
257
|
# Check if it cached the objects separately
|
|
155
|
-
key = "#{@post.cache_key}/#{adapter.
|
|
258
|
+
key = "#{@post.cache_key}/#{adapter.cache_key}"
|
|
156
259
|
assert_equal(@post_serializer.attributes, cache_store.fetch(key))
|
|
157
|
-
key = "#{@comment.cache_key}/#{adapter.
|
|
260
|
+
key = "#{@comment.cache_key}/#{adapter.cache_key}"
|
|
158
261
|
assert_equal(@comment_serializer.attributes, cache_store.fetch(key))
|
|
159
262
|
|
|
160
263
|
# Simulating update on comments relationship with Post
|
|
@@ -166,9 +269,9 @@ module ActiveModelSerializers
|
|
|
166
269
|
render_object_with_cache(@post)
|
|
167
270
|
|
|
168
271
|
# Check if the the new comment was cached
|
|
169
|
-
key = "#{new_comment.cache_key}/#{adapter.
|
|
272
|
+
key = "#{new_comment.cache_key}/#{adapter.cache_key}"
|
|
170
273
|
assert_equal(new_comment_serializer.attributes, cache_store.fetch(key))
|
|
171
|
-
key = "#{@post.cache_key}/#{adapter.
|
|
274
|
+
key = "#{@post.cache_key}/#{adapter.cache_key}"
|
|
172
275
|
assert_equal(@post_serializer.attributes, cache_store.fetch(key))
|
|
173
276
|
end
|
|
174
277
|
end
|
|
@@ -178,14 +281,14 @@ module ActiveModelSerializers
|
|
|
178
281
|
id: @location.id,
|
|
179
282
|
lat: @location.lat,
|
|
180
283
|
lng: @location.lng,
|
|
181
|
-
|
|
284
|
+
address: 'Nowhere'
|
|
182
285
|
}
|
|
183
286
|
|
|
184
287
|
hash = render_object_with_cache(@location)
|
|
185
288
|
|
|
186
289
|
assert_equal(hash, expected_result)
|
|
187
|
-
key = "#{@location.cache_key}/#{adapter.
|
|
188
|
-
assert_equal({
|
|
290
|
+
key = "#{@location.cache_key}/#{adapter.cache_key}"
|
|
291
|
+
assert_equal({ address: 'Nowhere' }, cache_store.fetch(key))
|
|
189
292
|
end
|
|
190
293
|
|
|
191
294
|
def test_fragment_cache_with_inheritance
|
|
@@ -204,9 +307,9 @@ module ActiveModelSerializers
|
|
|
204
307
|
|
|
205
308
|
# Based on original failing test by @kevintyll
|
|
206
309
|
# rubocop:disable Metrics/AbcSize
|
|
207
|
-
def
|
|
310
|
+
def test_a_serializer_rendered_by_two_adapter_returns_differently_fetch_attributes
|
|
208
311
|
Object.const_set(:Alert, Class.new(ActiveModelSerializers::Model) do
|
|
209
|
-
|
|
312
|
+
attributes :id, :status, :resource, :started_at, :ended_at, :updated_at, :created_at
|
|
210
313
|
end)
|
|
211
314
|
Object.const_set(:UncachedAlertSerializer, Class.new(ActiveModel::Serializer) do
|
|
212
315
|
attributes :id, :status, :resource, :started_at, :ended_at, :updated_at, :created_at
|
|
@@ -225,7 +328,7 @@ module ActiveModelSerializers
|
|
|
225
328
|
created_at: Time.new(2016, 3, 31, 21, 37, 35, 0)
|
|
226
329
|
)
|
|
227
330
|
|
|
228
|
-
|
|
331
|
+
expected_fetch_attributes = {
|
|
229
332
|
id: 1,
|
|
230
333
|
status: 'fail',
|
|
231
334
|
resource: 'resource-1',
|
|
@@ -233,7 +336,7 @@ module ActiveModelSerializers
|
|
|
233
336
|
ended_at: nil,
|
|
234
337
|
updated_at: alert.updated_at,
|
|
235
338
|
created_at: alert.created_at
|
|
236
|
-
}
|
|
339
|
+
}.with_indifferent_access
|
|
237
340
|
expected_cached_jsonapi_attributes = {
|
|
238
341
|
id: '1',
|
|
239
342
|
type: 'alerts',
|
|
@@ -245,15 +348,15 @@ module ActiveModelSerializers
|
|
|
245
348
|
updated_at: alert.updated_at,
|
|
246
349
|
created_at: alert.created_at
|
|
247
350
|
}
|
|
248
|
-
}
|
|
351
|
+
}.with_indifferent_access
|
|
249
352
|
|
|
250
353
|
# Assert attributes are serialized correctly
|
|
251
354
|
serializable_alert = serializable(alert, serializer: AlertSerializer, adapter: :attributes)
|
|
252
|
-
attributes_serialization = serializable_alert.as_json
|
|
253
|
-
assert_equal
|
|
355
|
+
attributes_serialization = serializable_alert.as_json.with_indifferent_access
|
|
356
|
+
assert_equal expected_fetch_attributes, alert.attributes
|
|
254
357
|
assert_equal alert.attributes, attributes_serialization
|
|
255
358
|
attributes_cache_key = serializable_alert.adapter.serializer.cache_key(serializable_alert.adapter)
|
|
256
|
-
assert_equal attributes_serialization, cache_store.fetch(attributes_cache_key)
|
|
359
|
+
assert_equal attributes_serialization, cache_store.fetch(attributes_cache_key).with_indifferent_access
|
|
257
360
|
|
|
258
361
|
serializable_alert = serializable(alert, serializer: AlertSerializer, adapter: :json_api)
|
|
259
362
|
jsonapi_cache_key = serializable_alert.adapter.serializer.cache_key(serializable_alert.adapter)
|
|
@@ -265,7 +368,7 @@ module ActiveModelSerializers
|
|
|
265
368
|
serializable_alert = serializable(alert, serializer: UncachedAlertSerializer, adapter: :json_api)
|
|
266
369
|
assert_equal serializable_alert.as_json, jsonapi_serialization
|
|
267
370
|
|
|
268
|
-
cached_serialization = cache_store.fetch(jsonapi_cache_key)
|
|
371
|
+
cached_serialization = cache_store.fetch(jsonapi_cache_key).with_indifferent_access
|
|
269
372
|
assert_equal expected_cached_jsonapi_attributes, cached_serialization
|
|
270
373
|
ensure
|
|
271
374
|
Object.send(:remove_const, :Alert)
|
|
@@ -276,43 +379,83 @@ module ActiveModelSerializers
|
|
|
276
379
|
|
|
277
380
|
def test_uses_file_digest_in_cache_key
|
|
278
381
|
render_object_with_cache(@blog)
|
|
279
|
-
|
|
382
|
+
file_digest = Digest::MD5.hexdigest(File.open(__FILE__).read)
|
|
383
|
+
key = "#{@blog.cache_key}/#{adapter.cache_key}/#{file_digest}"
|
|
280
384
|
assert_equal(@blog_serializer.attributes, cache_store.fetch(key))
|
|
281
385
|
end
|
|
282
386
|
|
|
283
387
|
def test_cache_digest_definition
|
|
284
|
-
|
|
388
|
+
file_digest = Digest::MD5.hexdigest(File.open(__FILE__).read)
|
|
389
|
+
assert_equal(file_digest, @post_serializer.class._cache_digest)
|
|
285
390
|
end
|
|
286
391
|
|
|
287
392
|
def test_object_cache_keys
|
|
288
393
|
serializable = ActiveModelSerializers::SerializableResource.new([@comment, @comment])
|
|
289
|
-
|
|
394
|
+
include_directive = JSONAPI::IncludeDirective.new('*', allow_wildcard: true)
|
|
290
395
|
|
|
291
|
-
actual = ActiveModel::Serializer.object_cache_keys(serializable.adapter.serializer, serializable.adapter,
|
|
396
|
+
actual = ActiveModel::Serializer.object_cache_keys(serializable.adapter.serializer, serializable.adapter, include_directive)
|
|
292
397
|
|
|
293
398
|
assert_equal 3, actual.size
|
|
294
|
-
|
|
295
|
-
assert actual.any? { |key| key
|
|
296
|
-
|
|
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}'"
|
|
297
405
|
end
|
|
298
406
|
|
|
299
|
-
|
|
300
|
-
|
|
407
|
+
# rubocop:disable Metrics/AbcSize
|
|
408
|
+
def test_fetch_attributes_from_cache
|
|
409
|
+
serializers = ActiveModel::Serializer::CollectionSerializer.new([@comment, @comment])
|
|
301
410
|
|
|
302
411
|
Timecop.freeze(Time.current) do
|
|
303
412
|
render_object_with_cache(@comment)
|
|
304
413
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
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
|
|
308
423
|
|
|
309
|
-
assert_equal cached_attributes["#{@comment.cache_key}/#{
|
|
310
|
-
assert_equal cached_attributes["#{@comment.post.cache_key}/#{
|
|
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
|
|
311
426
|
|
|
312
427
|
writer = @comment.post.blog.writer
|
|
313
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
|
|
314
438
|
|
|
315
|
-
|
|
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
|
|
316
459
|
end
|
|
317
460
|
end
|
|
318
461
|
|
|
@@ -429,25 +572,53 @@ module ActiveModelSerializers
|
|
|
429
572
|
end
|
|
430
573
|
|
|
431
574
|
def test_fragment_fetch_with_virtual_attributes
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
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)
|
|
437
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)
|
|
438
600
|
expected_result = {
|
|
439
|
-
id: @
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
name: @role.name
|
|
601
|
+
id: @bio.id,
|
|
602
|
+
rating: nil,
|
|
603
|
+
content: @bio.content
|
|
443
604
|
}
|
|
444
|
-
|
|
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)
|
|
445
615
|
end
|
|
446
616
|
|
|
447
617
|
def test_fragment_fetch_with_namespaced_object
|
|
448
618
|
@spam = Spam::UnrelatedLink.new(id: 'spam-id-1')
|
|
449
619
|
@spam_serializer = Spam::UnrelatedLinkSerializer.new(@spam)
|
|
450
|
-
|
|
620
|
+
adapter_instance = ActiveModelSerializers::Adapter.configured_adapter.new(@spam_serializer)
|
|
621
|
+
@spam_hash = @spam_serializer.fetch_attributes_fragment(adapter_instance)
|
|
451
622
|
expected_result = {
|
|
452
623
|
id: @spam.id
|
|
453
624
|
}
|
|
@@ -476,10 +647,5 @@ module ActiveModelSerializers
|
|
|
476
647
|
def adapter
|
|
477
648
|
@serializable_resource.adapter
|
|
478
649
|
end
|
|
479
|
-
|
|
480
|
-
def cached_serialization(serializer)
|
|
481
|
-
cache_key = serializer.cache_key(adapter)
|
|
482
|
-
cache_store.fetch(cache_key)
|
|
483
|
-
end
|
|
484
650
|
end
|
|
485
651
|
end
|
|
@@ -3,15 +3,28 @@ require 'test_helper'
|
|
|
3
3
|
module ActiveModel
|
|
4
4
|
class Serializer
|
|
5
5
|
class CollectionSerializerTest < ActiveSupport::TestCase
|
|
6
|
-
|
|
6
|
+
class SingularModel < ::Model; end
|
|
7
|
+
class SingularModelSerializer < ActiveModel::Serializer
|
|
8
|
+
end
|
|
9
|
+
class HasManyModel < ::Model
|
|
10
|
+
associations :singular_models
|
|
11
|
+
end
|
|
12
|
+
class HasManyModelSerializer < ActiveModel::Serializer
|
|
13
|
+
has_many :singular_models
|
|
14
|
+
|
|
15
|
+
def custom_options
|
|
16
|
+
instance_options
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
class MessagesSerializer < ActiveModel::Serializer
|
|
7
20
|
type 'messages'
|
|
8
21
|
end
|
|
9
22
|
|
|
10
23
|
def setup
|
|
11
|
-
@
|
|
12
|
-
@
|
|
13
|
-
@resource = build_named_collection @
|
|
14
|
-
@serializer = collection_serializer.new(@resource,
|
|
24
|
+
@singular_model = SingularModel.new
|
|
25
|
+
@has_many_model = HasManyModel.new
|
|
26
|
+
@resource = build_named_collection @singular_model, @has_many_model
|
|
27
|
+
@serializer = collection_serializer.new(@resource, some: :options)
|
|
15
28
|
end
|
|
16
29
|
|
|
17
30
|
def collection_serializer
|
|
@@ -34,29 +47,29 @@ module ActiveModel
|
|
|
34
47
|
def test_each_object_should_be_serialized_with_appropriate_serializer
|
|
35
48
|
serializers = @serializer.to_a
|
|
36
49
|
|
|
37
|
-
assert_kind_of
|
|
38
|
-
assert_kind_of
|
|
50
|
+
assert_kind_of SingularModelSerializer, serializers.first
|
|
51
|
+
assert_kind_of SingularModel, serializers.first.object
|
|
39
52
|
|
|
40
|
-
assert_kind_of
|
|
41
|
-
assert_kind_of
|
|
53
|
+
assert_kind_of HasManyModelSerializer, serializers.last
|
|
54
|
+
assert_kind_of HasManyModel, serializers.last.object
|
|
42
55
|
|
|
43
56
|
assert_equal :options, serializers.last.custom_options[:some]
|
|
44
57
|
end
|
|
45
58
|
|
|
46
59
|
def test_serializer_option_not_passed_to_each_serializer
|
|
47
|
-
serializers = collection_serializer.new([@
|
|
60
|
+
serializers = collection_serializer.new([@has_many_model], serializer: HasManyModelSerializer).to_a
|
|
48
61
|
|
|
49
62
|
refute serializers.first.custom_options.key?(:serializer)
|
|
50
63
|
end
|
|
51
64
|
|
|
52
65
|
def test_root_default
|
|
53
|
-
@serializer = collection_serializer.new([@
|
|
66
|
+
@serializer = collection_serializer.new([@singular_model, @has_many_model])
|
|
54
67
|
assert_nil @serializer.root
|
|
55
68
|
end
|
|
56
69
|
|
|
57
70
|
def test_root
|
|
58
71
|
expected = 'custom_root'
|
|
59
|
-
@serializer = collection_serializer.new([@
|
|
72
|
+
@serializer = collection_serializer.new([@singular_model, @has_many_model], root: expected)
|
|
60
73
|
assert_equal expected, @serializer.root
|
|
61
74
|
end
|
|
62
75
|
|
|
@@ -80,12 +93,16 @@ module ActiveModel
|
|
|
80
93
|
resource = []
|
|
81
94
|
resource.define_singleton_method(:name) { nil }
|
|
82
95
|
serializer = collection_serializer.new(resource)
|
|
83
|
-
|
|
96
|
+
assert_raise ArgumentError do
|
|
97
|
+
serializer.json_key
|
|
98
|
+
end
|
|
84
99
|
end
|
|
85
100
|
|
|
86
101
|
def test_json_key_with_resource_without_name_and_no_serializers
|
|
87
102
|
serializer = collection_serializer.new([])
|
|
88
|
-
|
|
103
|
+
assert_raise ArgumentError do
|
|
104
|
+
serializer.json_key
|
|
105
|
+
end
|
|
89
106
|
end
|
|
90
107
|
|
|
91
108
|
def test_json_key_with_empty_resources_with_serializer
|
|
@@ -47,16 +47,6 @@ module ARModels
|
|
|
47
47
|
has_many :comments
|
|
48
48
|
belongs_to :author
|
|
49
49
|
end
|
|
50
|
-
|
|
51
|
-
class Comment < ActiveRecord::Base
|
|
52
|
-
belongs_to :post
|
|
53
|
-
belongs_to :author
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
class Author < ActiveRecord::Base
|
|
57
|
-
has_many :posts
|
|
58
|
-
end
|
|
59
|
-
|
|
60
50
|
class PostSerializer < ActiveModel::Serializer
|
|
61
51
|
attributes :id, :title, :body
|
|
62
52
|
|
|
@@ -64,15 +54,60 @@ module ARModels
|
|
|
64
54
|
belongs_to :author
|
|
65
55
|
end
|
|
66
56
|
|
|
57
|
+
class Comment < ActiveRecord::Base
|
|
58
|
+
belongs_to :post
|
|
59
|
+
belongs_to :author
|
|
60
|
+
end
|
|
67
61
|
class CommentSerializer < ActiveModel::Serializer
|
|
68
62
|
attributes :id, :contents
|
|
69
63
|
|
|
70
64
|
belongs_to :author
|
|
71
65
|
end
|
|
72
66
|
|
|
67
|
+
class Author < ActiveRecord::Base
|
|
68
|
+
has_many :posts
|
|
69
|
+
end
|
|
73
70
|
class AuthorSerializer < ActiveModel::Serializer
|
|
74
71
|
attributes :id, :name
|
|
75
72
|
|
|
76
73
|
has_many :posts
|
|
77
74
|
end
|
|
78
75
|
end
|
|
76
|
+
|
|
77
|
+
class Employee < ActiveRecord::Base
|
|
78
|
+
has_many :pictures, as: :imageable
|
|
79
|
+
has_many :object_tags, as: :taggable
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
class PolymorphicSimpleSerializer < ActiveModel::Serializer
|
|
83
|
+
attributes :id
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
class ObjectTag < ActiveRecord::Base
|
|
87
|
+
belongs_to :poly_tag
|
|
88
|
+
belongs_to :taggable, polymorphic: true
|
|
89
|
+
end
|
|
90
|
+
class PolymorphicObjectTagSerializer < ActiveModel::Serializer
|
|
91
|
+
attributes :id
|
|
92
|
+
belongs_to :taggable, serializer: PolymorphicSimpleSerializer, polymorphic: true
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
class PolyTag < ActiveRecord::Base
|
|
96
|
+
has_many :object_tags
|
|
97
|
+
end
|
|
98
|
+
class PolymorphicTagSerializer < ActiveModel::Serializer
|
|
99
|
+
attributes :id, :phrase
|
|
100
|
+
has_many :object_tags, serializer: PolymorphicObjectTagSerializer
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
class Picture < ActiveRecord::Base
|
|
104
|
+
belongs_to :imageable, polymorphic: true
|
|
105
|
+
has_many :object_tags, as: :taggable
|
|
106
|
+
end
|
|
107
|
+
class PolymorphicHasManySerializer < ActiveModel::Serializer
|
|
108
|
+
attributes :id, :name
|
|
109
|
+
end
|
|
110
|
+
class PolymorphicBelongsToSerializer < ActiveModel::Serializer
|
|
111
|
+
attributes :id, :title
|
|
112
|
+
belongs_to :imageable, serializer: PolymorphicHasManySerializer, polymorphic: true
|
|
113
|
+
end
|