active_model_serializers 0.10.0 → 0.10.3

Sign up to get free protection for your applications and to get access to all the features.
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