Skip to content

Commit 54aa6aa

Browse files
committed
Merge branch 'LcpMarvel-support_read_multi'
Followup: - Changelog
2 parents fb48bce + 43312fa commit 54aa6aa

File tree

3 files changed

+103
-3
lines changed

3 files changed

+103
-3
lines changed

lib/active_model/serializer/adapter/attributes.rb

Lines changed: 36 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ class Attributes < Base
55
def initialize(serializer, options = {})
66
super
77
@include_tree = IncludeTree.from_include_args(options[:include] || '*')
8+
@cached_attributes = options[:cache_attributes] || {}
89
end
910

1011
def serializable_hash(options = nil)
@@ -24,9 +25,38 @@ def fragment_cache(cached_hash, non_cached_hash)
2425
private
2526

2627
def serializable_hash_for_collection(options)
28+
cache_attributes
29+
2730
serializer.map { |s| Attributes.new(s, instance_options).serializable_hash(options) }
2831
end
2932

33+
# Read cache from cache_store
34+
# @return [Hash]
35+
def cache_read_multi
36+
return {} if ActiveModelSerializers.config.cache_store.blank?
37+
38+
keys = CachedSerializer.object_cache_keys(serializer, @include_tree)
39+
40+
return {} if keys.blank?
41+
42+
ActiveModelSerializers.config.cache_store.read_multi(*keys)
43+
end
44+
45+
# Set @cached_attributes
46+
def cache_attributes
47+
return if @cached_attributes.present?
48+
49+
@cached_attributes = cache_read_multi
50+
end
51+
52+
# Get attributes from @cached_attributes
53+
# @return [Hash] cached attributes
54+
def cached_attributes(cached_serializer)
55+
return yield unless cached_serializer.cached?
56+
57+
@cached_attributes.fetch(cached_serializer.cache_key) { yield }
58+
end
59+
3060
def serializable_hash_for_single_resource(options)
3161
resource = resource_object_for(options)
3262
relationships = resource_relationships(options)
@@ -56,8 +86,12 @@ def include_meta(json)
5686
end
5787

5888
def resource_object_for(options)
59-
cache_check(serializer) do
60-
serializer.attributes(options[:fields])
89+
cached_serializer = CachedSerializer.new(serializer)
90+
91+
cached_attributes(cached_serializer) do
92+
cached_serializer.cache_check(self) do
93+
serializer.attributes(options[:fields])
94+
end
6195
end
6296
end
6397
end

lib/active_model/serializer/adapter/cached_serializer.rb

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,17 +28,51 @@ def fragment_cached?
2828
end
2929

3030
def cache_key
31+
return @cache_key if defined?(@cache_key)
32+
3133
parts = []
3234
parts << object_cache_key
3335
parts << @klass._cache_digest unless @klass._cache_options && @klass._cache_options[:skip_digest]
34-
parts.join('/')
36+
@cache_key = parts.join('/')
3537
end
3638

3739
def object_cache_key
3840
object_time_safe = @cached_serializer.object.updated_at
3941
object_time_safe = object_time_safe.strftime('%Y%m%d%H%M%S%9N') if object_time_safe.respond_to?(:strftime)
4042
(@klass._cache_key) ? "#{@klass._cache_key}/#{@cached_serializer.object.id}-#{object_time_safe}" : @cached_serializer.object.cache_key
4143
end
44+
45+
# find all cache_key for the collection_serializer
46+
# @param collection_serializer
47+
# @param include_tree
48+
# @return [Array] all cache_key of collection_serializer
49+
def self.object_cache_keys(serializers, include_tree)
50+
cache_keys = []
51+
52+
serializers.each do |serializer|
53+
cache_keys << object_cache_key(serializer)
54+
55+
serializer.associations(include_tree).each do |association|
56+
if association.serializer.respond_to?(:each)
57+
association.serializer.each do |sub_serializer|
58+
cache_keys << object_cache_key(sub_serializer)
59+
end
60+
else
61+
cache_keys << object_cache_key(association.serializer)
62+
end
63+
end
64+
end
65+
66+
cache_keys.compact.uniq
67+
end
68+
69+
# @return [String, nil] the cache_key of the serializer or nil
70+
def self.object_cache_key(serializer)
71+
return unless serializer.present? && serializer.object.present?
72+
73+
cached_serializer = new(serializer)
74+
cached_serializer.cached? ? cached_serializer.cache_key : nil
75+
end
4276
end
4377
end
4478
end

test/serializers/cache_test.rb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,38 @@ def test_cache_digest_definition
149149
assert_equal(::Model::FILE_DIGEST, @post_serializer.class._cache_digest)
150150
end
151151

152+
def test_object_cache_keys
153+
serializer = CollectionSerializer.new([@comment, @comment])
154+
include_tree = IncludeTree.from_include_args('*')
155+
156+
actual = Serializer::Adapter::CachedSerializer.object_cache_keys(serializer, include_tree)
157+
158+
assert_equal actual.size, 3
159+
assert actual.any? { |key| key == 'comment/1' }
160+
assert actual.any? { |key| key =~ %r{post/post-\d+} }
161+
assert actual.any? { |key| key =~ %r{writer/author-\d+} }
162+
end
163+
164+
def test_cached_attributes
165+
serializer = CollectionSerializer.new([@comment, @comment])
166+
167+
Timecop.freeze(Time.now) do
168+
render_object_with_cache(@comment)
169+
170+
attributes = ActiveModel::Serializer::Adapter::Attributes.new(serializer)
171+
attributes.send(:cache_attributes)
172+
cached_attributes = attributes.instance_variable_get(:@cached_attributes)
173+
174+
assert_equal cached_attributes[@comment.cache_key], Comment.new(id: 1, body: 'ZOMG A COMMENT').attributes
175+
assert_equal cached_attributes[@comment.post.cache_key], Post.new(id: 'post', title: 'New Post', body: 'Body').attributes
176+
177+
writer = @comment.post.blog.writer
178+
writer_cache_key = "writer/#{writer.id}-#{writer.updated_at.strftime("%Y%m%d%H%M%S%9N")}"
179+
180+
assert_equal cached_attributes[writer_cache_key], Author.new(id: 'author', name: 'Joao M. D. Moura').attributes
181+
end
182+
end
183+
152184
def test_serializer_file_path_on_nix
153185
path = '/Users/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb'
154186
caller_line = "#{path}:1:in `<top (required)>'"

0 commit comments

Comments
 (0)