@@ -7,7 +7,6 @@ module Caching
7
7
included do
8
8
with_options instance_writer : false , instance_reader : false do |serializer |
9
9
serializer . class_attribute :_cache # @api private : the cache store
10
- serializer . class_attribute :_fragmented # @api private : Used ONLY by FragmentedSerializer to reference original serializer
11
10
serializer . class_attribute :_cache_key # @api private : when present, is first item in cache_key. Ignored if the serializable object defines #cache_key.
12
11
serializer . class_attribute :_cache_only # @api private : when fragment caching, whitelists fetch_attributes. Cannot combine with except
13
12
serializer . class_attribute :_cache_except # @api private : when fragment caching, blacklists fetch_attributes. Cannot combine with only
@@ -69,12 +68,15 @@ def _skip_digest?
69
68
_cache_options && _cache_options [ :skip_digest ]
70
69
end
71
70
72
- def cached_attributes
73
- _cache_only ? _cache_only : _attributes - _cache_except
74
- end
75
-
76
- def non_cached_attributes
77
- _attributes - cached_attributes
71
+ def fragmented_attributes
72
+ cached = _cache_only ? _cache_only : _attributes - _cache_except
73
+ cached = cached . map! { |field | _attributes_keys . fetch ( field , field ) }
74
+ non_cached = _attributes - cached
75
+ non_cached = non_cached . map! { |field | _attributes_keys . fetch ( field , field ) }
76
+ {
77
+ cached : cached ,
78
+ non_cached : non_cached
79
+ }
78
80
end
79
81
80
82
# Enables a serializer to be automatically cached
@@ -205,13 +207,13 @@ def fetch_attributes(fields, cached_attributes, adapter_instance)
205
207
key = cache_key ( adapter_instance )
206
208
cached_attributes . fetch ( key ) do
207
209
self . class . cache_store . fetch ( key , self . class . _cache_options ) do
208
- attributes ( fields )
210
+ attributes ( fields , true )
209
211
end
210
212
end
211
213
elsif self . class . fragment_cache_enabled?
212
- fetch_fragment_cache ( adapter_instance )
214
+ fetch_attributes_fragment ( adapter_instance )
213
215
else
214
- attributes ( fields )
216
+ attributes ( fields , true )
215
217
end
216
218
end
217
219
@@ -225,74 +227,40 @@ def fetch(adapter_instance, cache_options = self.class._cache_options)
225
227
end
226
228
end
227
229
228
- # 1. Create a CachedSerializer from the serializer class
229
- # 2. Serialize the above two with the given adapter
230
- # 3. Pass their serializations to the adapter +::fragment_cache+
231
- #
232
- # It will split the serializer into two, one that will be cached and one that will not
233
- #
234
- # Given a resource name
235
- # 1. Dynamically creates a CachedSerializer
236
- # for a given class 'name'
237
- # 2. Call
238
- # CachedSerializer.cache(serializer._cache_options)
239
- # CachedSerializer._fragmented = serializer
240
- # 3. Build a hash keyed to the +cached+ and +non_cached+ serializers
241
- # 4. Call +cached_attributes+ on the serializer class and the above hash
242
- # 5. Return the hash
243
- #
244
- # @example
245
- # When +name+ is <tt>User::Admin</tt>
246
- # creates the Serializer classes (if they don't exist).
247
- # CachedUser_AdminSerializer
248
- #
249
- # Given a hash of its cached and non-cached serializers
250
- # 1. Determine cached attributes from serializer class options
251
- # 2. Add cached attributes to cached Serializer
252
- # 3. Add non-cached attributes to non-cached Serializer
253
- def fetch_fragment_cache ( adapter_instance )
230
+ # 1. Determine cached fields from serializer class options
231
+ # 2. Get non_cached_fields and fetch cache_fields
232
+ # 3. Merge the two hashes using adapter_instance#fragment_cache
233
+ def fetch_attributes_fragment ( adapter_instance )
254
234
self . class . _cache_options ||= { }
255
235
self . class . _cache_options [ :key ] = self . class . _cache_key if self . class . _cache_key
236
+ options = { include_directive : ActiveModel ::Serializer . include_directive_from_options ( { } ) }
237
+ fields = self . class . fragmented_attributes
238
+
239
+ non_cached_fields = fields [ :non_cached ] . dup
240
+ non_cached_hash = attributes ( non_cached_fields , true )
241
+ ( non_cached_fields - non_cached_hash . keys ) . each do |missing_field |
242
+ # TODO: use _attributes_keys?
243
+ # gets any other associations, etc.
244
+ non_cached_hash [ missing_field ] = read_attribute_for_serialization ( missing_field )
245
+ end
256
246
257
- cached_serializer = _get_or_create_fragment_cached_serializer
258
- cached_hash = ActiveModelSerializers ::SerializableResource . new (
259
- object ,
260
- serializer : cached_serializer ,
261
- adapter : adapter_instance . class
262
- ) . serializable_hash
263
-
264
- fields = self . class . non_cached_attributes
265
- non_cached_hash = attributes ( fields , true )
247
+ cached_fields = fields [ :cached ] . dup
248
+ key = cache_key ( adapter_instance )
249
+ cached_hash =
250
+ self . class . cache_store . fetch ( key , self . class . _cache_options ) do
251
+ hash = attributes ( cached_fields , true )
252
+ ( cached_fields - hash . keys ) . each do |missing_field |
253
+ # TODO: use _attributes_keys?
254
+ # gets any other associations, etc.
255
+ hash [ missing_field ] = read_attribute_for_serialization ( missing_field )
256
+ end
257
+ hash
258
+ end
266
259
267
260
# Merge both results
268
261
adapter_instance . fragment_cache ( cached_hash , non_cached_hash )
269
262
end
270
263
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 ) )
286
- cached_serializer . cache ( self . class . _cache_options )
287
- cached_serializer . type ( self . class . _type )
288
- cached_serializer . _fragmented = self
289
- self . class . cached_attributes . each do |attribute |
290
- options = self . class . _attributes_keys [ attribute ] || { }
291
- cached_serializer . attribute ( attribute , options )
292
- end
293
- cached_serializer
294
- end
295
-
296
264
def cache_key ( adapter_instance )
297
265
return @cache_key if defined? ( @cache_key )
298
266
0 commit comments