@@ -72,34 +72,34 @@ def persistent(name, **opts, &block)
7272 end
7373 end
7474
75- ##
7675 # Cache an ActiveRecord collection. Supports only a basic collection of one type of object. Column selections or
7776 # joins etc. will NOT be respected when the collection is read back out.
7877 # @param name [String] cache key name
7978 # @param value [ActiveRecord::Relation] collection to cache
8079 # @param opts [Hash] options hash - any unlisted options will be passed to the underlying cache
8180 # @option opts [Boolean] :include_community whether to include the community ID in the cache key
8281 def write_collection ( name , value , **opts )
83- types = value . map ( &:class ) . uniq
84- if types . size > 1
85- raise TypeError , "Can't cache more than one type of object via write_collection"
86- end
87-
88- data = [ types [ 0 ] . to_s , *value . map ( &:id ) ]
89- namespaced = construct_ns_key ( name , include_community : include_community ( opts ) )
90- @underlying . write ( namespaced , data , **opts )
82+ check_collection ( value )
83+ data = NamespacedEnvCache . normalize_collection ( value )
84+ write_collection_data ( name , data , **opts )
9185 end
9286
93- ##
9487 # Read an ActiveRecord collection from cache. Returns a basic collection of the records that were cached, with
9588 # no selects or joins applied.
9689 # @param name [String] cache key name
9790 # @param opts [Hash] options hash - any unlisted options will be passed to the underlying cache
9891 # @options opts [Boolean] :include_community whether to include the community ID in the cache key
92+ # @return [ActiveRecord::Relation, nil]
9993 def read_collection ( name , **opts )
10094 namespaced = construct_ns_key ( name , include_community : include_community ( opts ) )
10195 data = @underlying . read ( namespaced , **opts )
10296 return nil if data . nil?
97+
98+ if data . is_a? ( ActiveRecord ::Relation )
99+ data = NamespacedEnvCache . normalize_collection ( data )
100+ write_collection_data ( name , data , **opts )
101+ end
102+
103103 type = data . slice! ( 0 )
104104 begin
105105 type . constantize . where ( id : data )
@@ -109,7 +109,6 @@ def read_collection(name, **opts)
109109 end
110110 end
111111
112- ##
113112 # Fetch an ActiveRecord collection from cache if it is present, otherwise cache the value returned by +block+.
114113 # @param name [String] cache key name
115114 # @param opts [Hash] options hash - any unlisted options will be passed to the underlying cache
@@ -131,6 +130,13 @@ def fetch_collection(name, **opts, &block)
131130 end
132131 end
133132
133+ # Normalizes a given ActiveRecord collection for use with the cache
134+ # @param value [ActiveRecord::Relation] collection to normalize
135+ # @return [[String, Integer, Integer, ...]]
136+ def self . normalize_collection ( value )
137+ [ value [ 0 ] . class . to_s , *value . map ( &:id ) ]
138+ end
139+
134140 # We have to statically report that we support cache versioning even though this depends on the underlying class.
135141 # However, this is not really a problem since all cache stores provided by activesupport support the feature and
136142 # we only use the redis cache (by activesupport) for QPixel.
@@ -140,10 +146,28 @@ def self.supports_cache_versioning?
140146
141147 private
142148
149+ # Raises an error if a given collection is not cacheable
150+ # @param value [ActiveRecord::Relation] collection to check
151+ def check_collection ( value )
152+ types = value . map ( &:class ) . uniq
153+ if types . size > 1
154+ raise TypeError , "Can't cache more than one type of object"
155+ end
156+ end
157+
143158 def construct_ns_key ( key , include_community : true )
144159 key = expanded_key ( key )
145160 c_id = RequestContext . community_id if include_community
146161 "#{ Rails . env } ://#{ [ c_id , key ] . compact . join ( '/' ) } "
147162 end
163+
164+ # Writes normalized collection data to the underlying cache
165+ # @param name [String] cache key name
166+ # @param data [[String, Integer, Integer, ...]] normalized collection data
167+ # @param opts [Hash] options hash - see #write_collection
168+ def write_collection_data ( name , data , **opts )
169+ namespaced = construct_ns_key ( name , include_community : include_community ( opts ) )
170+ @underlying . write ( namespaced , data , **opts )
171+ end
148172 end
149173end
0 commit comments