active_model_serializers 0.10.0 → 0.10.3

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 (146) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +2 -4
  3. data/.travis.yml +9 -1
  4. data/CHANGELOG.md +81 -2
  5. data/CODE_OF_CONDUCT.md +74 -0
  6. data/Gemfile +5 -2
  7. data/README.md +24 -24
  8. data/Rakefile +3 -3
  9. data/active_model_serializers.gemspec +20 -24
  10. data/docs/ARCHITECTURE.md +6 -7
  11. data/docs/README.md +2 -0
  12. data/docs/general/adapters.md +4 -2
  13. data/docs/general/caching.md +7 -1
  14. data/docs/general/configuration_options.md +70 -1
  15. data/docs/general/deserialization.md +1 -1
  16. data/docs/general/fields.md +31 -0
  17. data/docs/general/rendering.md +42 -3
  18. data/docs/general/serializers.md +97 -8
  19. data/docs/howto/add_pagination_links.md +4 -5
  20. data/docs/howto/add_relationship_links.md +137 -0
  21. data/docs/howto/add_root_key.md +4 -0
  22. data/docs/howto/grape_integration.md +42 -0
  23. data/docs/howto/outside_controller_use.md +9 -2
  24. data/docs/howto/passing_arbitrary_options.md +2 -2
  25. data/docs/howto/test.md +2 -0
  26. data/docs/howto/upgrade_from_0_8_to_0_10.md +265 -0
  27. data/docs/integrations/ember-and-json-api.md +64 -32
  28. data/docs/jsonapi/schema.md +1 -1
  29. data/lib/action_controller/serialization.rb +13 -3
  30. data/lib/active_model/serializer/adapter/base.rb +2 -0
  31. data/lib/active_model/serializer/array_serializer.rb +8 -5
  32. data/lib/active_model/serializer/association.rb +19 -4
  33. data/lib/active_model/serializer/belongs_to_reflection.rb +0 -3
  34. data/lib/active_model/serializer/collection_serializer.rb +35 -12
  35. data/lib/active_model/serializer/{associations.rb → concerns/associations.rb} +13 -11
  36. data/lib/active_model/serializer/{attributes.rb → concerns/attributes.rb} +0 -0
  37. data/lib/active_model/serializer/{caching.rb → concerns/caching.rb} +72 -113
  38. data/lib/active_model/serializer/{configuration.rb → concerns/configuration.rb} +25 -1
  39. data/lib/active_model/serializer/{links.rb → concerns/links.rb} +0 -0
  40. data/lib/active_model/serializer/{meta.rb → concerns/meta.rb} +0 -0
  41. data/lib/active_model/serializer/{type.rb → concerns/type.rb} +0 -0
  42. data/lib/active_model/serializer/error_serializer.rb +11 -7
  43. data/lib/active_model/serializer/errors_serializer.rb +25 -20
  44. data/lib/active_model/serializer/has_many_reflection.rb +0 -3
  45. data/lib/active_model/serializer/has_one_reflection.rb +0 -3
  46. data/lib/active_model/serializer/lint.rb +134 -130
  47. data/lib/active_model/serializer/reflection.rb +37 -21
  48. data/lib/active_model/serializer/version.rb +1 -1
  49. data/lib/active_model/serializer.rb +76 -37
  50. data/lib/active_model_serializers/adapter/attributes.rb +3 -66
  51. data/lib/active_model_serializers/adapter/base.rb +38 -38
  52. data/lib/active_model_serializers/adapter/json_api/link.rb +1 -1
  53. data/lib/active_model_serializers/adapter/json_api/pagination_links.rb +8 -1
  54. data/lib/active_model_serializers/adapter/json_api/relationship.rb +30 -19
  55. data/lib/active_model_serializers/adapter/json_api/resource_identifier.rb +23 -9
  56. data/lib/active_model_serializers/adapter/json_api.rb +44 -43
  57. data/lib/active_model_serializers/adapter.rb +6 -0
  58. data/lib/active_model_serializers/deprecate.rb +1 -2
  59. data/lib/active_model_serializers/deserialization.rb +2 -0
  60. data/lib/active_model_serializers/key_transform.rb +4 -0
  61. data/lib/active_model_serializers/lookup_chain.rb +80 -0
  62. data/lib/active_model_serializers/model.rb +4 -2
  63. data/lib/active_model_serializers/railtie.rb +3 -1
  64. data/lib/active_model_serializers/register_jsonapi_renderer.rb +44 -31
  65. data/lib/active_model_serializers/serializable_resource.rb +6 -5
  66. data/lib/active_model_serializers/serialization_context.rb +10 -3
  67. data/lib/active_model_serializers.rb +7 -0
  68. data/lib/generators/rails/serializer_generator.rb +4 -4
  69. data/lib/grape/active_model_serializers.rb +7 -5
  70. data/lib/grape/formatters/active_model_serializers.rb +19 -2
  71. data/lib/grape/helpers/active_model_serializers.rb +1 -0
  72. data/test/action_controller/adapter_selector_test.rb +4 -4
  73. data/test/action_controller/explicit_serializer_test.rb +5 -4
  74. data/test/action_controller/json/include_test.rb +106 -27
  75. data/test/action_controller/json_api/errors_test.rb +6 -7
  76. data/test/action_controller/json_api/fields_test.rb +57 -0
  77. data/test/action_controller/json_api/linked_test.rb +29 -24
  78. data/test/action_controller/json_api/pagination_test.rb +19 -19
  79. data/test/action_controller/json_api/transform_test.rb +3 -3
  80. data/test/action_controller/lookup_proc_test.rb +49 -0
  81. data/test/action_controller/namespace_lookup_test.rb +226 -0
  82. data/test/action_controller/serialization_test.rb +10 -7
  83. data/test/active_model_serializers/json_pointer_test.rb +15 -13
  84. data/test/active_model_serializers/key_transform_test.rb +286 -252
  85. data/test/active_model_serializers/model_test.rb +17 -4
  86. data/test/active_model_serializers/register_jsonapi_renderer_test_isolated.rb +143 -0
  87. data/test/active_model_serializers/serialization_context_test_isolated.rb +23 -10
  88. data/test/adapter/attributes_test.rb +43 -0
  89. data/test/adapter/json/collection_test.rb +14 -0
  90. data/test/adapter/json/transform_test.rb +15 -15
  91. data/test/adapter/json_api/collection_test.rb +4 -3
  92. data/test/adapter/json_api/errors_test.rb +17 -19
  93. data/test/adapter/json_api/fields_test.rb +4 -3
  94. data/test/adapter/json_api/has_many_test.rb +39 -18
  95. data/test/adapter/json_api/include_data_if_sideloaded_test.rb +166 -0
  96. data/test/adapter/json_api/json_api_test.rb +5 -7
  97. data/test/adapter/json_api/linked_test.rb +33 -12
  98. data/test/adapter/json_api/links_test.rb +4 -2
  99. data/test/adapter/json_api/pagination_links_test.rb +35 -8
  100. data/test/adapter/json_api/relationship_test.rb +309 -73
  101. data/test/adapter/json_api/resource_identifier_test.rb +27 -2
  102. data/test/adapter/json_api/resource_meta_test.rb +3 -3
  103. data/test/adapter/json_api/transform_test.rb +255 -253
  104. data/test/adapter/json_api/type_test.rb +1 -1
  105. data/test/adapter/json_test.rb +8 -7
  106. data/test/adapter/null_test.rb +1 -2
  107. data/test/adapter/polymorphic_test.rb +5 -5
  108. data/test/adapter_test.rb +1 -1
  109. data/test/benchmark/app.rb +1 -1
  110. data/test/benchmark/benchmarking_support.rb +1 -1
  111. data/test/benchmark/bm_active_record.rb +81 -0
  112. data/test/benchmark/bm_adapter.rb +38 -0
  113. data/test/benchmark/bm_caching.rb +16 -16
  114. data/test/benchmark/bm_lookup_chain.rb +83 -0
  115. data/test/benchmark/bm_transform.rb +16 -5
  116. data/test/benchmark/controllers.rb +16 -17
  117. data/test/benchmark/fixtures.rb +72 -72
  118. data/test/cache_test.rb +143 -49
  119. data/test/collection_serializer_test.rb +3 -3
  120. data/test/fixtures/poro.rb +52 -48
  121. data/test/generators/serializer_generator_test.rb +22 -5
  122. data/test/grape_test.rb +152 -56
  123. data/test/lint_test.rb +1 -1
  124. data/test/logger_test.rb +13 -11
  125. data/test/serializable_resource_test.rb +18 -22
  126. data/test/serializers/association_macros_test.rb +3 -2
  127. data/test/serializers/associations_test.rb +107 -32
  128. data/test/serializers/attribute_test.rb +2 -2
  129. data/test/serializers/attributes_test.rb +1 -1
  130. data/test/serializers/fieldset_test.rb +1 -1
  131. data/test/serializers/meta_test.rb +12 -6
  132. data/test/serializers/root_test.rb +1 -1
  133. data/test/serializers/serializer_for_test.rb +6 -4
  134. data/test/serializers/serializer_for_with_namespace_test.rb +87 -0
  135. data/test/support/isolated_unit.rb +5 -2
  136. data/test/support/rails5_shims.rb +8 -2
  137. data/test/support/rails_app.rb +0 -9
  138. data/test/support/serialization_testing.rb +23 -5
  139. data/test/test_helper.rb +1 -0
  140. metadata +85 -34
  141. data/.rubocop_todo.yml +0 -167
  142. data/lib/active_model/serializer/include_tree.rb +0 -111
  143. data/test/adapter/json_api/relationships_test.rb +0 -199
  144. data/test/include_tree/from_include_args_test.rb +0 -26
  145. data/test/include_tree/from_string_test.rb +0 -94
  146. data/test/include_tree/include_args_to_hash_test.rb +0 -64
@@ -1,33 +1,33 @@
1
1
  Rails.configuration.serializers = []
2
- class AuthorSerializer < ActiveModel::Serializer
2
+ class HasOneRelationshipSerializer < ActiveModel::Serializer
3
3
  attributes :id, :first_name, :last_name
4
4
 
5
- has_many :posts, embed: :ids
5
+ has_many :primary_resources, embed: :ids
6
6
  has_one :bio
7
7
  end
8
- Rails.configuration.serializers << AuthorSerializer
8
+ Rails.configuration.serializers << HasOneRelationshipSerializer
9
9
 
10
- class BlogSerializer < ActiveModel::Serializer
10
+ class VirtualAttributeSerializer < ActiveModel::Serializer
11
11
  attributes :id, :name
12
12
  end
13
- Rails.configuration.serializers << BlogSerializer
13
+ Rails.configuration.serializers << VirtualAttributeSerializer
14
14
 
15
- class CommentSerializer < ActiveModel::Serializer
16
- attributes :id, :body, :updated_at
15
+ class HasManyRelationshipSerializer < ActiveModel::Serializer
16
+ attributes :id, :body
17
17
 
18
- belongs_to :post
19
- belongs_to :author
18
+ belongs_to :primary_resource
19
+ belongs_to :has_one_relationship
20
20
  end
21
- Rails.configuration.serializers << CommentSerializer
21
+ Rails.configuration.serializers << HasManyRelationshipSerializer
22
22
 
23
- class PostSerializer < ActiveModel::Serializer
23
+ class PrimaryResourceSerializer < ActiveModel::Serializer
24
24
  attributes :id, :title, :body
25
25
 
26
- has_many :comments, serializer: CommentSerializer
27
- belongs_to :blog, serializer: BlogSerializer
28
- belongs_to :author, serializer: AuthorSerializer
26
+ has_many :has_many_relationships, serializer: HasManyRelationshipSerializer
27
+ belongs_to :virtual_attribute, serializer: VirtualAttributeSerializer
28
+ belongs_to :has_one_relationship, serializer: HasOneRelationshipSerializer
29
29
 
30
- link(:post_authors) { 'https://example.com/post_authors' }
30
+ link(:primary_resource_has_one_relationships) { 'https://example.com/primary_resource_has_one_relationships' }
31
31
 
32
32
  meta do
33
33
  {
@@ -36,33 +36,33 @@ class PostSerializer < ActiveModel::Serializer
36
36
  }
37
37
  end
38
38
 
39
- def blog
40
- Blog.new(id: 999, name: 'Custom blog')
39
+ def virtual_attribute
40
+ VirtualAttribute.new(id: 999, name: 'Free-Range Virtual Attribute')
41
41
  end
42
42
  end
43
- Rails.configuration.serializers << PostSerializer
43
+ Rails.configuration.serializers << PrimaryResourceSerializer
44
44
 
45
- class CachingAuthorSerializer < AuthorSerializer
45
+ class CachingHasOneRelationshipSerializer < HasOneRelationshipSerializer
46
46
  cache key: 'writer', skip_digest: true
47
47
  end
48
- Rails.configuration.serializers << CachingAuthorSerializer
48
+ Rails.configuration.serializers << CachingHasOneRelationshipSerializer
49
49
 
50
- class CachingCommentSerializer < CommentSerializer
50
+ class CachingHasManyRelationshipSerializer < HasManyRelationshipSerializer
51
51
  cache expires_in: 1.day, skip_digest: true
52
52
  end
53
- Rails.configuration.serializers << CachingCommentSerializer
53
+ Rails.configuration.serializers << CachingHasManyRelationshipSerializer
54
54
 
55
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
56
+ class CachingPrimaryResourceSerializer < ActiveModel::Serializer
57
+ cache key: 'primary_resource', expires_in: 0.1, skip_digest: true
58
58
 
59
59
  attributes :id, :title, :body
60
60
 
61
- belongs_to :blog, serializer: BlogSerializer
62
- belongs_to :author, serializer: CachingAuthorSerializer
63
- has_many :comments, serializer: CachingCommentSerializer
61
+ belongs_to :virtual_attribute, serializer: VirtualAttributeSerializer
62
+ belongs_to :has_one_relationship, serializer: CachingHasOneRelationshipSerializer
63
+ has_many :has_many_relationships, serializer: CachingHasManyRelationshipSerializer
64
64
 
65
- link(:post_authors) { 'https://example.com/post_authors' }
65
+ link(:primary_resource_has_one_relationships) { 'https://example.com/primary_resource_has_one_relationships' }
66
66
 
67
67
  meta do
68
68
  {
@@ -71,33 +71,33 @@ class CachingPostSerializer < ActiveModel::Serializer
71
71
  }
72
72
  end
73
73
 
74
- def blog
75
- Blog.new(id: 999, name: 'Custom blog')
74
+ def virtual_attribute
75
+ VirtualAttribute.new(id: 999, name: 'Free-Range Virtual Attribute')
76
76
  end
77
77
  end
78
- Rails.configuration.serializers << CachingPostSerializer
78
+ Rails.configuration.serializers << CachingPrimaryResourceSerializer
79
79
 
80
- class FragmentCachingAuthorSerializer < AuthorSerializer
80
+ class FragmentCachingHasOneRelationshipSerializer < HasOneRelationshipSerializer
81
81
  cache key: 'writer', only: [:first_name, :last_name], skip_digest: true
82
82
  end
83
- Rails.configuration.serializers << FragmentCachingAuthorSerializer
83
+ Rails.configuration.serializers << FragmentCachingHasOneRelationshipSerializer
84
84
 
85
- class FragmentCachingCommentSerializer < CommentSerializer
86
- cache expires_in: 1.day, except: [:updated_at], skip_digest: true
85
+ class FragmentCachingHasManyRelationshipSerializer < HasManyRelationshipSerializer
86
+ cache expires_in: 1.day, except: [:body], skip_digest: true
87
87
  end
88
- Rails.configuration.serializers << CachingCommentSerializer
88
+ Rails.configuration.serializers << CachingHasManyRelationshipSerializer
89
89
 
90
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
91
+ class FragmentCachingPrimaryResourceSerializer < ActiveModel::Serializer
92
+ cache key: 'primary_resource', expires_in: 0.1, skip_digest: true
93
93
 
94
94
  attributes :id, :title, :body
95
95
 
96
- belongs_to :blog, serializer: BlogSerializer
97
- belongs_to :author, serializer: FragmentCachingAuthorSerializer
98
- has_many :comments, serializer: FragmentCachingCommentSerializer
96
+ belongs_to :virtual_attribute, serializer: VirtualAttributeSerializer
97
+ belongs_to :has_one_relationship, serializer: FragmentCachingHasOneRelationshipSerializer
98
+ has_many :has_many_relationships, serializer: FragmentCachingHasManyRelationshipSerializer
99
99
 
100
- link(:post_authors) { 'https://example.com/post_authors' }
100
+ link(:primary_resource_has_one_relationships) { 'https://example.com/primary_resource_has_one_relationships' }
101
101
 
102
102
  meta do
103
103
  {
@@ -106,11 +106,11 @@ class FragmentCachingPostSerializer < ActiveModel::Serializer
106
106
  }
107
107
  end
108
108
 
109
- def blog
110
- Blog.new(id: 999, name: 'Custom blog')
109
+ def virtual_attribute
110
+ VirtualAttribute.new(id: 999, name: 'Free-Range Virtual Attribute')
111
111
  end
112
112
  end
113
- Rails.configuration.serializers << FragmentCachingPostSerializer
113
+ Rails.configuration.serializers << FragmentCachingPrimaryResourceSerializer
114
114
 
115
115
  if ENV['ENABLE_ACTIVE_RECORD'] == 'true'
116
116
  require 'active_record'
@@ -119,48 +119,48 @@ if ENV['ENABLE_ACTIVE_RECORD'] == 'true'
119
119
  ActiveRecord::Schema.define do
120
120
  self.verbose = false
121
121
 
122
- create_table :blogs, force: true do |t|
122
+ create_table :virtual_attributes, force: true do |t|
123
123
  t.string :name
124
124
  t.timestamps null: false
125
125
  end
126
- create_table :authors, force: true do |t|
126
+ create_table :has_one_relationships, force: true do |t|
127
127
  t.string :first_name
128
128
  t.string :last_name
129
129
  t.timestamps null: false
130
130
  end
131
- create_table :posts, force: true do |t|
131
+ create_table :primary_resources, force: true do |t|
132
132
  t.string :title
133
133
  t.text :body
134
- t.references :author
135
- t.references :blog
134
+ t.references :has_one_relationship
135
+ t.references :virtual_attribute
136
136
  t.timestamps null: false
137
137
  end
138
- create_table :comments, force: true do |t|
138
+ create_table :has_many_relationships, force: true do |t|
139
139
  t.text :body
140
- t.references :author
141
- t.references :post
140
+ t.references :has_one_relationship
141
+ t.references :primary_resource
142
142
  t.timestamps null: false
143
143
  end
144
144
  end
145
145
 
146
- class Comment < ActiveRecord::Base
147
- belongs_to :author
148
- belongs_to :post
146
+ class HasManyRelationship < ActiveRecord::Base
147
+ belongs_to :has_one_relationship
148
+ belongs_to :primary_resource
149
149
  end
150
150
 
151
- class Author < ActiveRecord::Base
152
- has_many :posts
153
- has_many :comments
151
+ class HasOneRelationship < ActiveRecord::Base
152
+ has_many :primary_resources
153
+ has_many :has_many_relationships
154
154
  end
155
155
 
156
- class Post < ActiveRecord::Base
157
- has_many :comments
158
- belongs_to :author
159
- belongs_to :blog
156
+ class PrimaryResource < ActiveRecord::Base
157
+ has_many :has_many_relationships
158
+ belongs_to :has_one_relationship
159
+ belongs_to :virtual_attribute
160
160
  end
161
161
 
162
- class Blog < ActiveRecord::Base
163
- has_many :posts
162
+ class VirtualAttribute < ActiveRecord::Base
163
+ has_many :primary_resources
164
164
  end
165
165
  else
166
166
  # ActiveModelSerializers::Model is a convenient
@@ -201,19 +201,19 @@ else
201
201
  end
202
202
  end
203
203
 
204
- class Comment < BenchmarkModel
205
- attr_accessor :id, :body, :updated_at
204
+ class HasManyRelationship < BenchmarkModel
205
+ attr_accessor :id, :body
206
206
  end
207
207
 
208
- class Author < BenchmarkModel
209
- attr_accessor :id, :first_name, :last_name, :posts
208
+ class HasOneRelationship < BenchmarkModel
209
+ attr_accessor :id, :first_name, :last_name, :primary_resources
210
210
  end
211
211
 
212
- class Post < BenchmarkModel
213
- attr_accessor :id, :title, :body, :comments, :blog, :author
212
+ class PrimaryResource < BenchmarkModel
213
+ attr_accessor :id, :title, :body, :has_many_relationships, :virtual_attribute, :has_one_relationship
214
214
  end
215
215
 
216
- class Blog < BenchmarkModel
216
+ class VirtualAttribute < BenchmarkModel
217
217
  attr_accessor :id, :name
218
218
  end
219
219
  end
data/test/cache_test.rb CHANGED
@@ -4,22 +4,46 @@ require 'tempfile'
4
4
 
5
5
  module ActiveModelSerializers
6
6
  class CacheTest < ActiveSupport::TestCase
7
- UncachedAuthor = Class.new(Author) do
7
+ # Instead of a primitive cache key (i.e. a string), this class
8
+ # returns a list of objects that require to be expanded themselves.
9
+ class AuthorWithExpandableCacheElements < Author
10
+ # For the test purposes it's important that #to_s for HasCacheKey differs
11
+ # between instances, hence not a Struct.
12
+ class HasCacheKey
13
+ attr_reader :cache_key
14
+ def initialize(cache_key)
15
+ @cache_key = cache_key
16
+ end
17
+
18
+ def to_s
19
+ "HasCacheKey##{object_id}"
20
+ end
21
+ end
22
+
23
+ def cache_key
24
+ [
25
+ HasCacheKey.new(name),
26
+ HasCacheKey.new(id)
27
+ ]
28
+ end
29
+ end
30
+
31
+ class UncachedAuthor < Author
8
32
  # To confirm cache_key is set using updated_at and cache_key option passed to cache
9
33
  undef_method :cache_key
10
34
  end
11
35
 
12
- Article = Class.new(::Model) do
36
+ class Article < ::Model
13
37
  # To confirm error is raised when cache_key is not set and cache_key option not passed to cache
14
38
  undef_method :cache_key
15
39
  end
16
40
 
17
- ArticleSerializer = Class.new(ActiveModel::Serializer) do
41
+ class ArticleSerializer < ActiveModel::Serializer
18
42
  cache only: [:place], skip_digest: true
19
43
  attributes :title
20
44
  end
21
45
 
22
- InheritedRoleSerializer = Class.new(RoleSerializer) do
46
+ class InheritedRoleSerializer < RoleSerializer
23
47
  cache key: 'inherited_role', only: [:name, :special_attribute]
24
48
  attribute :special_attribute
25
49
  end
@@ -101,14 +125,28 @@ module ActiveModelSerializers
101
125
  uncached_author_serializer = AuthorSerializer.new(uncached_author)
102
126
 
103
127
  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}"
128
+ 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')}"
129
+ key = "#{key}/#{adapter.cache_key}"
106
130
  assert_equal(uncached_author_serializer.attributes.to_json, cache_store.fetch(key).to_json)
107
131
  end
108
132
 
133
+ def test_cache_key_expansion
134
+ author = AuthorWithExpandableCacheElements.new(id: 10, name: 'hello')
135
+ same_author = AuthorWithExpandableCacheElements.new(id: 10, name: 'hello')
136
+ diff_author = AuthorWithExpandableCacheElements.new(id: 11, name: 'hello')
137
+
138
+ author_serializer = AuthorSerializer.new(author)
139
+ same_author_serializer = AuthorSerializer.new(same_author)
140
+ diff_author_serializer = AuthorSerializer.new(diff_author)
141
+ adapter = AuthorSerializer.serialization_adapter_instance
142
+
143
+ assert_equal(author_serializer.cache_key(adapter), same_author_serializer.cache_key(adapter))
144
+ refute_equal(author_serializer.cache_key(adapter), diff_author_serializer.cache_key(adapter))
145
+ end
146
+
109
147
  def test_default_cache_key_fallback
110
148
  render_object_with_cache(@comment)
111
- key = "#{@comment.cache_key}/#{adapter.cached_name}"
149
+ key = "#{@comment.cache_key}/#{adapter.cache_key}"
112
150
  assert_equal(@comment_serializer.attributes.to_json, cache_store.fetch(key).to_json)
113
151
  end
114
152
 
@@ -117,7 +155,7 @@ module ActiveModelSerializers
117
155
  e = assert_raises ActiveModel::Serializer::UndefinedCacheKey do
118
156
  render_object_with_cache(article)
119
157
  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)
158
+ assert_match(/ActiveModelSerializers::CacheTest::Article must define #cache_key, or the 'key:' option must be passed into 'ActiveModelSerializers::CacheTest::ArticleSerializer.cache'/, e.message)
121
159
  end
122
160
 
123
161
  def test_cache_options_definition
@@ -127,7 +165,7 @@ module ActiveModelSerializers
127
165
  end
128
166
 
129
167
  def test_fragment_cache_definition
130
- assert_equal([:name], @role_serializer.class._cache_only)
168
+ assert_equal([:name, :slug], @role_serializer.class._cache_only)
131
169
  assert_equal([:content], @bio_serializer.class._cache_except)
132
170
  end
133
171
 
@@ -139,9 +177,9 @@ module ActiveModelSerializers
139
177
  Timecop.freeze(Time.current) do
140
178
  render_object_with_cache(@post)
141
179
 
142
- key = "#{@post.cache_key}/#{adapter.cached_name}"
180
+ key = "#{@post.cache_key}/#{adapter.cache_key}"
143
181
  assert_equal(@post_serializer.attributes, cache_store.fetch(key))
144
- key = "#{@comment.cache_key}/#{adapter.cached_name}"
182
+ key = "#{@comment.cache_key}/#{adapter.cache_key}"
145
183
  assert_equal(@comment_serializer.attributes, cache_store.fetch(key))
146
184
  end
147
185
  end
@@ -152,9 +190,9 @@ module ActiveModelSerializers
152
190
  render_object_with_cache(@post)
153
191
 
154
192
  # Check if it cached the objects separately
155
- key = "#{@post.cache_key}/#{adapter.cached_name}"
193
+ key = "#{@post.cache_key}/#{adapter.cache_key}"
156
194
  assert_equal(@post_serializer.attributes, cache_store.fetch(key))
157
- key = "#{@comment.cache_key}/#{adapter.cached_name}"
195
+ key = "#{@comment.cache_key}/#{adapter.cache_key}"
158
196
  assert_equal(@comment_serializer.attributes, cache_store.fetch(key))
159
197
 
160
198
  # Simulating update on comments relationship with Post
@@ -166,9 +204,9 @@ module ActiveModelSerializers
166
204
  render_object_with_cache(@post)
167
205
 
168
206
  # Check if the the new comment was cached
169
- key = "#{new_comment.cache_key}/#{adapter.cached_name}"
207
+ key = "#{new_comment.cache_key}/#{adapter.cache_key}"
170
208
  assert_equal(new_comment_serializer.attributes, cache_store.fetch(key))
171
- key = "#{@post.cache_key}/#{adapter.cached_name}"
209
+ key = "#{@post.cache_key}/#{adapter.cache_key}"
172
210
  assert_equal(@post_serializer.attributes, cache_store.fetch(key))
173
211
  end
174
212
  end
@@ -178,14 +216,14 @@ module ActiveModelSerializers
178
216
  id: @location.id,
179
217
  lat: @location.lat,
180
218
  lng: @location.lng,
181
- place: 'Nowhere'
219
+ address: 'Nowhere'
182
220
  }
183
221
 
184
222
  hash = render_object_with_cache(@location)
185
223
 
186
224
  assert_equal(hash, expected_result)
187
- key = "#{@location.cache_key}/#{adapter.cached_name}"
188
- assert_equal({ place: 'Nowhere' }, cache_store.fetch(key))
225
+ key = "#{@location.cache_key}/#{adapter.cache_key}"
226
+ assert_equal({ address: 'Nowhere' }, cache_store.fetch(key))
189
227
  end
190
228
 
191
229
  def test_fragment_cache_with_inheritance
@@ -204,7 +242,7 @@ module ActiveModelSerializers
204
242
 
205
243
  # Based on original failing test by @kevintyll
206
244
  # rubocop:disable Metrics/AbcSize
207
- def test_a_serializer_rendered_by_two_adapter_returns_differently_cached_attributes
245
+ def test_a_serializer_rendered_by_two_adapter_returns_differently_fetch_attributes
208
246
  Object.const_set(:Alert, Class.new(ActiveModelSerializers::Model) do
209
247
  attr_accessor :id, :status, :resource, :started_at, :ended_at, :updated_at, :created_at
210
248
  end)
@@ -225,7 +263,7 @@ module ActiveModelSerializers
225
263
  created_at: Time.new(2016, 3, 31, 21, 37, 35, 0)
226
264
  )
227
265
 
228
- expected_cached_attributes = {
266
+ expected_fetch_attributes = {
229
267
  id: 1,
230
268
  status: 'fail',
231
269
  resource: 'resource-1',
@@ -250,7 +288,7 @@ module ActiveModelSerializers
250
288
  # Assert attributes are serialized correctly
251
289
  serializable_alert = serializable(alert, serializer: AlertSerializer, adapter: :attributes)
252
290
  attributes_serialization = serializable_alert.as_json
253
- assert_equal expected_cached_attributes, alert.attributes
291
+ assert_equal expected_fetch_attributes, alert.attributes
254
292
  assert_equal alert.attributes, attributes_serialization
255
293
  attributes_cache_key = serializable_alert.adapter.serializer.cache_key(serializable_alert.adapter)
256
294
  assert_equal attributes_serialization, cache_store.fetch(attributes_cache_key)
@@ -276,7 +314,7 @@ module ActiveModelSerializers
276
314
 
277
315
  def test_uses_file_digest_in_cache_key
278
316
  render_object_with_cache(@blog)
279
- key = "#{@blog.cache_key}/#{adapter.cached_name}/#{::Model::FILE_DIGEST}"
317
+ key = "#{@blog.cache_key}/#{adapter.cache_key}/#{::Model::FILE_DIGEST}"
280
318
  assert_equal(@blog_serializer.attributes, cache_store.fetch(key))
281
319
  end
282
320
 
@@ -286,33 +324,66 @@ module ActiveModelSerializers
286
324
 
287
325
  def test_object_cache_keys
288
326
  serializable = ActiveModelSerializers::SerializableResource.new([@comment, @comment])
289
- include_tree = ActiveModel::Serializer::IncludeTree.from_include_args('*')
327
+ include_directive = JSONAPI::IncludeDirective.new('*', allow_wildcard: true)
290
328
 
291
- actual = ActiveModel::Serializer.object_cache_keys(serializable.adapter.serializer, serializable.adapter, include_tree)
329
+ actual = ActiveModel::Serializer.object_cache_keys(serializable.adapter.serializer, serializable.adapter, include_directive)
292
330
 
293
331
  assert_equal 3, actual.size
294
- assert actual.any? { |key| key == "comment/1/#{serializable.adapter.cached_name}" }
332
+ assert actual.any? { |key| key == "comment/1/#{serializable.adapter.cache_key}" }
295
333
  assert actual.any? { |key| key =~ %r{post/post-\d+} }
296
334
  assert actual.any? { |key| key =~ %r{author/author-\d+} }
297
335
  end
298
336
 
299
- def test_cached_attributes
300
- serializer = ActiveModel::Serializer::CollectionSerializer.new([@comment, @comment])
337
+ def test_fetch_attributes_from_cache
338
+ serializers = ActiveModel::Serializer::CollectionSerializer.new([@comment, @comment])
301
339
 
302
340
  Timecop.freeze(Time.current) do
303
341
  render_object_with_cache(@comment)
304
342
 
305
- attributes = Adapter::Attributes.new(serializer)
306
- attributes.send(:cache_attributes)
307
- cached_attributes = attributes.instance_variable_get(:@cached_attributes)
343
+ options = {}
344
+ adapter_options = {}
345
+ adapter_instance = ActiveModelSerializers::Adapter::Attributes.new(serializers, adapter_options)
346
+ serializers.serializable_hash(adapter_options, options, adapter_instance)
347
+ cached_attributes = adapter_options.fetch(:cached_attributes)
348
+
349
+ include_directive = ActiveModelSerializers.default_include_directive
350
+ manual_cached_attributes = ActiveModel::Serializer.cache_read_multi(serializers, adapter_instance, include_directive)
351
+ assert_equal manual_cached_attributes, cached_attributes
308
352
 
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
353
+ assert_equal cached_attributes["#{@comment.cache_key}/#{adapter_instance.cache_key}"], Comment.new(id: 1, body: 'ZOMG A COMMENT').attributes
354
+ assert_equal cached_attributes["#{@comment.post.cache_key}/#{adapter_instance.cache_key}"], Post.new(id: 'post', title: 'New Post', body: 'Body').attributes
311
355
 
312
356
  writer = @comment.post.blog.writer
313
357
  writer_cache_key = writer.cache_key
358
+ assert_equal cached_attributes["#{writer_cache_key}/#{adapter_instance.cache_key}"], Author.new(id: 'author', name: 'Joao M. D. Moura').attributes
359
+ end
360
+ end
314
361
 
315
- assert_equal cached_attributes["#{writer_cache_key}/#{attributes.cached_name}"], Author.new(id: 'author', name: 'Joao M. D. Moura').attributes
362
+ def test_cache_read_multi_with_fragment_cache_enabled
363
+ post_serializer = Class.new(ActiveModel::Serializer) do
364
+ cache except: [:body]
365
+ end
366
+
367
+ serializers = ActiveModel::Serializer::CollectionSerializer.new([@post, @post], serializer: post_serializer)
368
+
369
+ Timecop.freeze(Time.current) do
370
+ # Warming up.
371
+ options = {}
372
+ adapter_options = {}
373
+ adapter_instance = ActiveModelSerializers::Adapter::Attributes.new(serializers, adapter_options)
374
+ serializers.serializable_hash(adapter_options, options, adapter_instance)
375
+
376
+ # Should find something with read_multi now
377
+ adapter_options = {}
378
+ serializers.serializable_hash(adapter_options, options, adapter_instance)
379
+ cached_attributes = adapter_options.fetch(:cached_attributes)
380
+
381
+ include_directive = ActiveModelSerializers.default_include_directive
382
+ manual_cached_attributes = ActiveModel::Serializer.cache_read_multi(serializers, adapter_instance, include_directive)
383
+
384
+ refute_equal 0, cached_attributes.size
385
+ refute_equal 0, manual_cached_attributes.size
386
+ assert_equal manual_cached_attributes, cached_attributes
316
387
  end
317
388
  end
318
389
 
@@ -429,25 +500,53 @@ module ActiveModelSerializers
429
500
  end
430
501
 
431
502
  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))
503
+ author = Author.new(name: 'Joao M. D. Moura')
504
+ role = Role.new(name: 'Great Author', description: nil)
505
+ role.author = [author]
506
+ role_serializer = RoleSerializer.new(role)
507
+ adapter_instance = ActiveModelSerializers::Adapter.configured_adapter.new(role_serializer)
508
+ expected_result = {
509
+ id: role.id,
510
+ description: role.description,
511
+ slug: "#{role.name}-#{role.id}",
512
+ name: role.name
513
+ }
514
+ cache_store.clear
515
+
516
+ role_hash = role_serializer.fetch_attributes_fragment(adapter_instance)
517
+ assert_equal(role_hash, expected_result)
518
+
519
+ role.attributes[:id] = 'this has been updated'
520
+ role.name = 'this was cached'
521
+
522
+ role_hash = role_serializer.fetch_attributes_fragment(adapter_instance)
523
+ assert_equal(expected_result.merge(id: role.id), role_hash)
524
+ end
437
525
 
526
+ def test_fragment_fetch_with_except
527
+ adapter_instance = ActiveModelSerializers::Adapter.configured_adapter.new(@bio_serializer)
438
528
  expected_result = {
439
- id: @role.id,
440
- description: @role.description,
441
- slug: "#{@role.name}-#{@role.id}",
442
- name: @role.name
529
+ id: @bio.id,
530
+ rating: nil,
531
+ content: @bio.content
443
532
  }
444
- assert_equal(@role_hash, expected_result)
533
+ cache_store.clear
534
+
535
+ bio_hash = @bio_serializer.fetch_attributes_fragment(adapter_instance)
536
+ assert_equal(expected_result, bio_hash)
537
+
538
+ @bio.content = 'this has been updated'
539
+ @bio.rating = 'this was cached'
540
+
541
+ bio_hash = @bio_serializer.fetch_attributes_fragment(adapter_instance)
542
+ assert_equal(expected_result.merge(content: @bio.content), bio_hash)
445
543
  end
446
544
 
447
545
  def test_fragment_fetch_with_namespaced_object
448
546
  @spam = Spam::UnrelatedLink.new(id: 'spam-id-1')
449
547
  @spam_serializer = Spam::UnrelatedLinkSerializer.new(@spam)
450
- @spam_hash = @spam_serializer.fetch_fragment_cache(ActiveModelSerializers::Adapter.configured_adapter.new(@spam_serializer))
548
+ adapter_instance = ActiveModelSerializers::Adapter.configured_adapter.new(@spam_serializer)
549
+ @spam_hash = @spam_serializer.fetch_attributes_fragment(adapter_instance)
451
550
  expected_result = {
452
551
  id: @spam.id
453
552
  }
@@ -476,10 +575,5 @@ module ActiveModelSerializers
476
575
  def adapter
477
576
  @serializable_resource.adapter
478
577
  end
479
-
480
- def cached_serialization(serializer)
481
- cache_key = serializer.cache_key(adapter)
482
- cache_store.fetch(cache_key)
483
- end
484
578
  end
485
579
  end
@@ -3,7 +3,7 @@ require 'test_helper'
3
3
  module ActiveModel
4
4
  class Serializer
5
5
  class CollectionSerializerTest < ActiveSupport::TestCase
6
- MessagesSerializer = Class.new(ActiveModel::Serializer) do
6
+ class MessagesSerializer < ActiveModel::Serializer
7
7
  type 'messages'
8
8
  end
9
9
 
@@ -11,7 +11,7 @@ module ActiveModel
11
11
  @comment = Comment.new
12
12
  @post = Post.new
13
13
  @resource = build_named_collection @comment, @post
14
- @serializer = collection_serializer.new(@resource, { some: :options })
14
+ @serializer = collection_serializer.new(@resource, some: :options)
15
15
  end
16
16
 
17
17
  def collection_serializer
@@ -44,7 +44,7 @@ module ActiveModel
44
44
  end
45
45
 
46
46
  def test_serializer_option_not_passed_to_each_serializer
47
- serializers = collection_serializer.new([@post], { serializer: PostSerializer }).to_a
47
+ serializers = collection_serializer.new([@post], serializer: PostSerializer).to_a
48
48
 
49
49
  refute serializers.first.custom_options.key?(:serializer)
50
50
  end