@@ -7,7 +7,6 @@ module Caching
77 included do
88 with_options instance_writer : false , instance_reader : false do |serializer |
99 serializer . class_attribute :_cache # @api private : the cache store
10- serializer . class_attribute :_fragmented # @api private : Used ONLY by FragmentedSerializer to reference original serializer
1110 serializer . class_attribute :_cache_key # @api private : when present, is first item in cache_key. Ignored if the serializable object defines #cache_key.
1211 serializer . class_attribute :_cache_only # @api private : when fragment caching, whitelists fetch_attributes. Cannot combine with except
1312 serializer . class_attribute :_cache_except # @api private : when fragment caching, blacklists fetch_attributes. Cannot combine with only
@@ -69,12 +68,15 @@ def _skip_digest?
6968 _cache_options && _cache_options [ :skip_digest ]
7069 end
7170
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+ }
7880 end
7981
8082 # Enables a serializer to be automatically cached
@@ -205,13 +207,13 @@ def fetch_attributes(fields, cached_attributes, adapter_instance)
205207 key = cache_key ( adapter_instance )
206208 cached_attributes . fetch ( key ) do
207209 self . class . cache_store . fetch ( key , self . class . _cache_options ) do
208- attributes ( fields )
210+ attributes ( fields , true )
209211 end
210212 end
211213 elsif self . class . fragment_cache_enabled?
212- fetch_fragment_cache ( adapter_instance )
214+ fetch_attributes_fragment ( adapter_instance )
213215 else
214- attributes ( fields )
216+ attributes ( fields , true )
215217 end
216218 end
217219
@@ -225,74 +227,40 @@ def fetch(adapter_instance, cache_options = self.class._cache_options)
225227 end
226228 end
227229
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 )
254234 self . class . _cache_options ||= { }
255235 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
256246
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
266259
267260 # Merge both results
268261 adapter_instance . fragment_cache ( cached_hash , non_cached_hash )
269262 end
270263
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-
296264 def cache_key ( adapter_instance )
297265 return @cache_key if defined? ( @cache_key )
298266
0 commit comments