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