1
- # TODO(BF): refactor file to be smaller
2
- # rubocop:disable Metrics/ModuleLength
3
1
module ActiveModel
4
2
class Serializer
5
3
UndefinedCacheKey = Class . new ( StandardError )
@@ -9,10 +7,10 @@ module Caching
9
7
included do
10
8
with_options instance_writer : false , instance_reader : false do |serializer |
11
9
serializer . class_attribute :_cache # @api private : the cache store
12
- serializer . class_attribute :_fragmented # @api private : @see ::fragmented
10
+ serializer . class_attribute :_fragmented # @api private : Used ONLY by FragmentedSerializer to reference original serializer
13
11
serializer . class_attribute :_cache_key # @api private : when present, is first item in cache_key. Ignored if the serializable object defines #cache_key.
14
- serializer . class_attribute :_cache_only # @api private : when fragment caching, whitelists cached_attributes . Cannot combine with except
15
- serializer . class_attribute :_cache_except # @api private : when fragment caching, blacklists cached_attributes . Cannot combine with only
12
+ serializer . class_attribute :_cache_only # @api private : when fragment caching, whitelists fetch_attributes . Cannot combine with except
13
+ serializer . class_attribute :_cache_except # @api private : when fragment caching, blacklists fetch_attributes . Cannot combine with only
16
14
serializer . class_attribute :_cache_options # @api private : used by CachedSerializer, passed to _cache.fetch
17
15
# _cache_options include:
18
16
# expires_in
@@ -79,13 +77,6 @@ def non_cached_attributes
79
77
_attributes - cached_attributes
80
78
end
81
79
82
- # @api private
83
- # Used by FragmentCache on the CachedSerializer
84
- # to call attribute methods on the fragmented cached serializer.
85
- def fragmented ( serializer )
86
- self . _fragmented = serializer
87
- end
88
-
89
80
# Enables a serializer to be automatically cached
90
81
#
91
82
# Sets +::_cache+ object to <tt>ActionController::Base.cache_store</tt>
@@ -208,46 +199,44 @@ def object_cache_key(serializer, adapter_instance)
208
199
end
209
200
end
210
201
211
- def cached_attributes ( fields , cached_attributes , adapter_instance )
202
+ ### INSTANCE METHODS
203
+ def fetch_attributes ( fields , cached_attributes , adapter_instance )
212
204
if self . class . cache_enabled?
213
205
key = cache_key ( adapter_instance )
214
206
cached_attributes . fetch ( key ) do
215
- cache_check ( adapter_instance ) do
207
+ self . class . cache_store . fetch ( key , self . class . _cache_options ) do
216
208
attributes ( fields )
217
209
end
218
210
end
211
+ elsif self . class . fragment_cache_enabled?
212
+ fetch_fragment_cache ( adapter_instance )
219
213
else
220
- cache_check ( adapter_instance ) do
221
- attributes ( fields )
222
- end
214
+ attributes ( fields )
223
215
end
224
216
end
225
217
226
- def cache_check ( adapter_instance )
227
- if self . class . cache_enabled?
228
- self . class . cache_store . fetch ( cache_key ( adapter_instance ) , self . class . _cache_options ) do
218
+ def fetch ( adapter_instance , cache_options = self . class . _cache_options )
219
+ if self . class . cache_store
220
+ self . class . cache_store . fetch ( cache_key ( adapter_instance ) , cache_options ) do
229
221
yield
230
222
end
231
- elsif self . class . fragment_cache_enabled?
232
- fetch_fragment_cache ( adapter_instance )
233
223
else
234
224
yield
235
225
end
236
226
end
237
227
238
- # 1. Create a CachedSerializer and NonCachedSerializer from the serializer class
228
+ # 1. Create a CachedSerializer from the serializer class
239
229
# 2. Serialize the above two with the given adapter
240
230
# 3. Pass their serializations to the adapter +::fragment_cache+
241
231
#
242
232
# It will split the serializer into two, one that will be cached and one that will not
243
233
#
244
234
# Given a resource name
245
- # 1. Dynamically creates a CachedSerializer and NonCachedSerializer
235
+ # 1. Dynamically creates a CachedSerializer
246
236
# for a given class 'name'
247
237
# 2. Call
248
238
# CachedSerializer.cache(serializer._cache_options)
249
- # CachedSerializer.fragmented(serializer)
250
- # NonCachedSerializer.cache(serializer._cache_options)
239
+ # CachedSerializer._fragmented = serializer
251
240
# 3. Build a hash keyed to the +cached+ and +non_cached+ serializers
252
241
# 4. Call +cached_attributes+ on the serializer class and the above hash
253
242
# 5. Return the hash
@@ -256,63 +245,54 @@ def cache_check(adapter_instance)
256
245
# When +name+ is <tt>User::Admin</tt>
257
246
# creates the Serializer classes (if they don't exist).
258
247
# CachedUser_AdminSerializer
259
- # NonCachedUser_AdminSerializer
260
248
#
261
249
# Given a hash of its cached and non-cached serializers
262
250
# 1. Determine cached attributes from serializer class options
263
251
# 2. Add cached attributes to cached Serializer
264
252
# 3. Add non-cached attributes to non-cached Serializer
265
253
def fetch_fragment_cache ( adapter_instance )
266
- serializer_class_name = self . class . name . gsub ( '::' . freeze , '_' . freeze )
267
254
self . class . _cache_options ||= { }
268
255
self . class . _cache_options [ :key ] = self . class . _cache_key if self . class . _cache_key
269
256
270
- cached_serializer = _get_or_create_fragment_cached_serializer ( serializer_class_name )
257
+ cached_serializer = _get_or_create_fragment_cached_serializer
271
258
cached_hash = ActiveModelSerializers ::SerializableResource . new (
272
259
object ,
273
260
serializer : cached_serializer ,
274
261
adapter : adapter_instance . class
275
262
) . serializable_hash
276
263
277
- non_cached_serializer = _get_or_create_fragment_non_cached_serializer ( serializer_class_name )
278
- non_cached_hash = ActiveModelSerializers ::SerializableResource . new (
279
- object ,
280
- serializer : non_cached_serializer ,
281
- adapter : adapter_instance . class
282
- ) . serializable_hash
264
+ fields = self . class . non_cached_attributes
265
+ non_cached_hash = attributes ( fields , true )
283
266
284
267
# Merge both results
285
268
adapter_instance . fragment_cache ( cached_hash , non_cached_hash )
286
269
end
287
270
288
- def _get_or_create_fragment_cached_serializer ( serializer_class_name )
289
- cached_serializer = _get_or_create_fragment_serializer "Cached#{ serializer_class_name } "
271
+ def _get_or_create_fragment_cached_serializer
272
+ serializer_class_name = self . class . name . gsub ( '::' . freeze , '_' . freeze )
273
+ cached_serializer_name = "Cached#{ serializer_class_name } "
274
+ if Object . const_defined? ( cached_serializer_name )
275
+ cached_serializer = Object . const_get ( cached_serializer_name )
276
+ # HACK: Test concern in production code :(
277
+ # But it's better than running all the cached fragment serializer
278
+ # code multiple times.
279
+ if Rails . env == 'test' . freeze
280
+ Object . send ( :remove_const , cached_serializer_name )
281
+ return _get_or_create_fragment_cached_serializer
282
+ end
283
+ return cached_serializer
284
+ end
285
+ cached_serializer = Object . const_set ( cached_serializer_name , Class . new ( ActiveModel ::Serializer ) )
290
286
cached_serializer . cache ( self . class . _cache_options )
291
287
cached_serializer . type ( self . class . _type )
292
- cached_serializer . fragmented ( self )
288
+ cached_serializer . _fragmented = self
293
289
self . class . cached_attributes . each do |attribute |
294
290
options = self . class . _attributes_keys [ attribute ] || { }
295
291
cached_serializer . attribute ( attribute , options )
296
292
end
297
293
cached_serializer
298
294
end
299
295
300
- def _get_or_create_fragment_non_cached_serializer ( serializer_class_name )
301
- non_cached_serializer = _get_or_create_fragment_serializer "NonCached#{ serializer_class_name } "
302
- non_cached_serializer . type ( self . class . _type )
303
- non_cached_serializer . fragmented ( self )
304
- self . class . non_cached_attributes . each do |attribute |
305
- options = self . class . _attributes_keys [ attribute ] || { }
306
- non_cached_serializer . attribute ( attribute , options )
307
- end
308
- non_cached_serializer
309
- end
310
-
311
- def _get_or_create_fragment_serializer ( name )
312
- return Object . const_get ( name ) if Object . const_defined? ( name )
313
- Object . const_set ( name , Class . new ( ActiveModel ::Serializer ) )
314
- end
315
-
316
296
def cache_key ( adapter_instance )
317
297
return @cache_key if defined? ( @cache_key )
318
298
@@ -339,4 +319,3 @@ def object_cache_key
339
319
end
340
320
end
341
321
end
342
- # rubocop:enable Metrics/ModuleLength
0 commit comments