1- # TODO(BF): refactor file to be smaller
2- # rubocop:disable Metrics/ModuleLength
31module ActiveModel
42 class Serializer
53 UndefinedCacheKey = Class . new ( StandardError )
@@ -9,10 +7,10 @@ module Caching
97 included do
108 with_options instance_writer : false , instance_reader : false do |serializer |
119 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
1311 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
1614 serializer . class_attribute :_cache_options # @api private : used by CachedSerializer, passed to _cache.fetch
1715 # _cache_options include:
1816 # expires_in
@@ -79,13 +77,6 @@ def non_cached_attributes
7977 _attributes - cached_attributes
8078 end
8179
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-
8980 # Enables a serializer to be automatically cached
9081 #
9182 # Sets +::_cache+ object to <tt>ActionController::Base.cache_store</tt>
@@ -208,46 +199,44 @@ def object_cache_key(serializer, adapter_instance)
208199 end
209200 end
210201
211- def cached_attributes ( fields , cached_attributes , adapter_instance )
202+ ### INSTANCE METHODS
203+ def fetch_attributes ( fields , cached_attributes , adapter_instance )
212204 if self . class . cache_enabled?
213205 key = cache_key ( adapter_instance )
214206 cached_attributes . fetch ( key ) do
215- cache_check ( adapter_instance ) do
207+ self . class . cache_store . fetch ( key , self . class . _cache_options ) do
216208 attributes ( fields )
217209 end
218210 end
211+ elsif self . class . fragment_cache_enabled?
212+ fetch_fragment_cache ( adapter_instance )
219213 else
220- cache_check ( adapter_instance ) do
221- attributes ( fields )
222- end
214+ attributes ( fields )
223215 end
224216 end
225217
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
229221 yield
230222 end
231- elsif self . class . fragment_cache_enabled?
232- fetch_fragment_cache ( adapter_instance )
233223 else
234224 yield
235225 end
236226 end
237227
238- # 1. Create a CachedSerializer and NonCachedSerializer from the serializer class
228+ # 1. Create a CachedSerializer from the serializer class
239229 # 2. Serialize the above two with the given adapter
240230 # 3. Pass their serializations to the adapter +::fragment_cache+
241231 #
242232 # It will split the serializer into two, one that will be cached and one that will not
243233 #
244234 # Given a resource name
245- # 1. Dynamically creates a CachedSerializer and NonCachedSerializer
235+ # 1. Dynamically creates a CachedSerializer
246236 # for a given class 'name'
247237 # 2. Call
248238 # CachedSerializer.cache(serializer._cache_options)
249- # CachedSerializer.fragmented(serializer)
250- # NonCachedSerializer.cache(serializer._cache_options)
239+ # CachedSerializer._fragmented = serializer
251240 # 3. Build a hash keyed to the +cached+ and +non_cached+ serializers
252241 # 4. Call +cached_attributes+ on the serializer class and the above hash
253242 # 5. Return the hash
@@ -256,63 +245,54 @@ def cache_check(adapter_instance)
256245 # When +name+ is <tt>User::Admin</tt>
257246 # creates the Serializer classes (if they don't exist).
258247 # CachedUser_AdminSerializer
259- # NonCachedUser_AdminSerializer
260248 #
261249 # Given a hash of its cached and non-cached serializers
262250 # 1. Determine cached attributes from serializer class options
263251 # 2. Add cached attributes to cached Serializer
264252 # 3. Add non-cached attributes to non-cached Serializer
265253 def fetch_fragment_cache ( adapter_instance )
266- serializer_class_name = self . class . name . gsub ( '::' . freeze , '_' . freeze )
267254 self . class . _cache_options ||= { }
268255 self . class . _cache_options [ :key ] = self . class . _cache_key if self . class . _cache_key
269256
270- cached_serializer = _get_or_create_fragment_cached_serializer ( serializer_class_name )
257+ cached_serializer = _get_or_create_fragment_cached_serializer
271258 cached_hash = ActiveModelSerializers ::SerializableResource . new (
272259 object ,
273260 serializer : cached_serializer ,
274261 adapter : adapter_instance . class
275262 ) . serializable_hash
276263
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 )
283266
284267 # Merge both results
285268 adapter_instance . fragment_cache ( cached_hash , non_cached_hash )
286269 end
287270
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 ) )
290286 cached_serializer . cache ( self . class . _cache_options )
291287 cached_serializer . type ( self . class . _type )
292- cached_serializer . fragmented ( self )
288+ cached_serializer . _fragmented = self
293289 self . class . cached_attributes . each do |attribute |
294290 options = self . class . _attributes_keys [ attribute ] || { }
295291 cached_serializer . attribute ( attribute , options )
296292 end
297293 cached_serializer
298294 end
299295
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-
316296 def cache_key ( adapter_instance )
317297 return @cache_key if defined? ( @cache_key )
318298
@@ -339,4 +319,3 @@ def object_cache_key
339319 end
340320 end
341321end
342- # rubocop:enable Metrics/ModuleLength
0 commit comments