From 43312fa083a28729f4314e9496a92a3bc7b1f507 Mon Sep 17 00:00:00 2001 From: lcp Date: Fri, 11 Dec 2015 17:38:01 +0800 Subject: [PATCH] support read_multi --- .../serializer/adapter/attributes.rb | 38 ++++++++++++++++++- .../serializer/adapter/cached_serializer.rb | 36 +++++++++++++++++- test/serializers/cache_test.rb | 32 ++++++++++++++++ 3 files changed, 103 insertions(+), 3 deletions(-) diff --git a/lib/active_model/serializer/adapter/attributes.rb b/lib/active_model/serializer/adapter/attributes.rb index 49dea860..657cd1f1 100644 --- a/lib/active_model/serializer/adapter/attributes.rb +++ b/lib/active_model/serializer/adapter/attributes.rb @@ -5,6 +5,7 @@ module ActiveModel def initialize(serializer, options = {}) super @include_tree = IncludeTree.from_include_args(options[:include] || '*') + @cached_attributes = options[:cache_attributes] || {} end def serializable_hash(options = nil) @@ -24,9 +25,38 @@ module ActiveModel private def serializable_hash_for_collection(options) + cache_attributes + serializer.map { |s| Attributes.new(s, instance_options).serializable_hash(options) } end + # Read cache from cache_store + # @return [Hash] + def cache_read_multi + return {} if ActiveModelSerializers.config.cache_store.blank? + + keys = CachedSerializer.object_cache_keys(serializer, @include_tree) + + return {} if keys.blank? + + ActiveModelSerializers.config.cache_store.read_multi(*keys) + end + + # Set @cached_attributes + def cache_attributes + return if @cached_attributes.present? + + @cached_attributes = cache_read_multi + end + + # Get attributes from @cached_attributes + # @return [Hash] cached attributes + def cached_attributes(cached_serializer) + return yield unless cached_serializer.cached? + + @cached_attributes.fetch(cached_serializer.cache_key) { yield } + end + def serializable_hash_for_single_resource(options) resource = resource_object_for(options) relationships = resource_relationships(options) @@ -56,8 +86,12 @@ module ActiveModel end def resource_object_for(options) - cache_check(serializer) do - serializer.attributes(options[:fields]) + cached_serializer = CachedSerializer.new(serializer) + + cached_attributes(cached_serializer) do + cached_serializer.cache_check(self) do + serializer.attributes(options[:fields]) + end end end end diff --git a/lib/active_model/serializer/adapter/cached_serializer.rb b/lib/active_model/serializer/adapter/cached_serializer.rb index 35b10168..358942bf 100644 --- a/lib/active_model/serializer/adapter/cached_serializer.rb +++ b/lib/active_model/serializer/adapter/cached_serializer.rb @@ -28,10 +28,12 @@ module ActiveModel end def cache_key + return @cache_key if defined?(@cache_key) + parts = [] parts << object_cache_key parts << @klass._cache_digest unless @klass._cache_options && @klass._cache_options[:skip_digest] - parts.join('/') + @cache_key = parts.join('/') end def object_cache_key @@ -39,6 +41,38 @@ module ActiveModel object_time_safe = object_time_safe.strftime('%Y%m%d%H%M%S%9N') if object_time_safe.respond_to?(:strftime) (@klass._cache_key) ? "#{@klass._cache_key}/#{@cached_serializer.object.id}-#{object_time_safe}" : @cached_serializer.object.cache_key end + + # find all cache_key for the collection_serializer + # @param collection_serializer + # @param include_tree + # @return [Array] all cache_key of collection_serializer + def self.object_cache_keys(serializers, include_tree) + cache_keys = [] + + serializers.each do |serializer| + cache_keys << object_cache_key(serializer) + + serializer.associations(include_tree).each do |association| + if association.serializer.respond_to?(:each) + association.serializer.each do |sub_serializer| + cache_keys << object_cache_key(sub_serializer) + end + else + cache_keys << object_cache_key(association.serializer) + end + end + end + + cache_keys.compact.uniq + end + + # @return [String, nil] the cache_key of the serializer or nil + def self.object_cache_key(serializer) + return unless serializer.present? && serializer.object.present? + + cached_serializer = new(serializer) + cached_serializer.cached? ? cached_serializer.cache_key : nil + end end end end diff --git a/test/serializers/cache_test.rb b/test/serializers/cache_test.rb index fea7f8f1..4290947b 100644 --- a/test/serializers/cache_test.rb +++ b/test/serializers/cache_test.rb @@ -149,6 +149,38 @@ module ActiveModel assert_equal(::Model::FILE_DIGEST, @post_serializer.class._cache_digest) end + def test_object_cache_keys + serializer = CollectionSerializer.new([@comment, @comment]) + include_tree = IncludeTree.from_include_args('*') + + actual = Serializer::Adapter::CachedSerializer.object_cache_keys(serializer, include_tree) + + assert_equal actual.size, 3 + assert actual.any? { |key| key == 'comment/1' } + assert actual.any? { |key| key =~ %r{post/post-\d+} } + assert actual.any? { |key| key =~ %r{writer/author-\d+} } + end + + def test_cached_attributes + serializer = CollectionSerializer.new([@comment, @comment]) + + Timecop.freeze(Time.now) do + render_object_with_cache(@comment) + + attributes = ActiveModel::Serializer::Adapter::Attributes.new(serializer) + attributes.send(:cache_attributes) + cached_attributes = attributes.instance_variable_get(:@cached_attributes) + + assert_equal cached_attributes[@comment.cache_key], Comment.new(id: 1, body: 'ZOMG A COMMENT').attributes + assert_equal cached_attributes[@comment.post.cache_key], Post.new(id: 'post', title: 'New Post', body: 'Body').attributes + + writer = @comment.post.blog.writer + writer_cache_key = "writer/#{writer.id}-#{writer.updated_at.strftime("%Y%m%d%H%M%S%9N")}" + + assert_equal cached_attributes[writer_cache_key], Author.new(id: 'author', name: 'Joao M. D. Moura').attributes + end + end + def test_serializer_file_path_on_nix path = '/Users/git/emberjs/ember-crm-backend/app/serializers/lead_serializer.rb' caller_line = "#{path}:1:in `'"