diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index 00eed5bc..4cbc681d 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -19,6 +19,7 @@ module ActiveModel attr_accessor :_cache_only attr_accessor :_cache_except attr_accessor :_cache_options + attr_accessor :_cache_digest end def self.inherited(base) @@ -26,6 +27,8 @@ module ActiveModel base._attributes_keys = self._attributes_keys.try(:dup) || {} base._associations = self._associations.try(:dup) || {} base._urls = [] + serializer_file = File.open(caller.first[/^[^:]+/]) + base._cache_digest = Digest::MD5.hexdigest(serializer_file.read) end def self.attributes(*attrs) diff --git a/lib/active_model/serializer/adapter.rb b/lib/active_model/serializer/adapter.rb index 2377247b..bc658ba2 100644 --- a/lib/active_model/serializer/adapter.rb +++ b/lib/active_model/serializer/adapter.rb @@ -63,6 +63,13 @@ module ActiveModel end def cache_key + parts = [] + parts << object_cache_key + parts << @klass._cache_digest unless @klass._cache_options && @klass._cache_options[:skip_digest] + parts.join("/") + end + + def object_cache_key (@klass._cache_key) ? "#{@klass._cache_key}/#{@cached_serializer.object.id}-#{@cached_serializer.object.updated_at}" : @cached_serializer.object.cache_key end diff --git a/test/fixtures/poro.rb b/test/fixtures/poro.rb index 84a24de3..0bef569c 100644 --- a/test/fixtures/poro.rb +++ b/test/fixtures/poro.rb @@ -1,4 +1,6 @@ class Model + FILE_DIGEST = Digest::MD5.hexdigest(File.open(__FILE__).read) + def initialize(hash={}) @attributes = hash end @@ -7,6 +9,10 @@ class Model "#{self.class.name.downcase}/#{self.id}-#{self.updated_at}" end + def cache_key_with_digest + "#{cache_key}/#{FILE_DIGEST}" + end + def updated_at @attributes[:updated_at] ||= DateTime.now.to_time.to_i end @@ -72,7 +78,7 @@ module Spam; end Spam::UnrelatedLink = Class.new(Model) PostSerializer = Class.new(ActiveModel::Serializer) do - cache key:'post', expires_in: 0.1 + cache key:'post', expires_in: 0.1, skip_digest: true attributes :id, :title, :body has_many :comments @@ -99,7 +105,7 @@ SpammyPostSerializer = Class.new(ActiveModel::Serializer) do end CommentSerializer = Class.new(ActiveModel::Serializer) do - cache expires_in: 1.day + cache expires_in: 1.day, skip_digest: true attributes :id, :body belongs_to :post @@ -111,7 +117,7 @@ CommentSerializer = Class.new(ActiveModel::Serializer) do end AuthorSerializer = Class.new(ActiveModel::Serializer) do - cache key:'writer' + cache key:'writer', skip_digest: true attributes :id, :name has_many :posts, embed: :ids @@ -120,7 +126,7 @@ AuthorSerializer = Class.new(ActiveModel::Serializer) do end RoleSerializer = Class.new(ActiveModel::Serializer) do - cache only: [:name] + cache only: [:name], skip_digest: true attributes :id, :name, :description, :slug def slug @@ -137,7 +143,7 @@ LikeSerializer = Class.new(ActiveModel::Serializer) do end LocationSerializer = Class.new(ActiveModel::Serializer) do - cache only: [:place] + cache only: [:place], skip_digest: true attributes :id, :lat, :lng belongs_to :place @@ -154,13 +160,14 @@ PlaceSerializer = Class.new(ActiveModel::Serializer) do end BioSerializer = Class.new(ActiveModel::Serializer) do - cache except: [:content] + cache except: [:content], skip_digest: true attributes :id, :content, :rating belongs_to :author end BlogSerializer = Class.new(ActiveModel::Serializer) do + cache key: 'blog' attributes :id, :name belongs_to :writer diff --git a/test/serializers/cache_test.rb b/test/serializers/cache_test.rb index 89c62a21..eb0f9e0d 100644 --- a/test/serializers/cache_test.rb +++ b/test/serializers/cache_test.rb @@ -5,10 +5,10 @@ module ActiveModel def setup ActionController::Base.cache_store.clear @comment = Comment.new(id: 1, body: 'ZOMG A COMMENT') - @blog = Blog.new(id: 999, name: "Custom blog") @post = Post.new(title: 'New Post', body: 'Body') @bio = Bio.new(id: 1, content: 'AMS Contributor') @author = Author.new(name: 'Joao M. D. Moura') + @blog = Blog.new(id: 999, name: "Custom blog", writer: @author, articles: []) @role = Role.new(name: 'Great Author') @location = Location.new(lat: '-23.550520', lng: '-46.633309') @place = Place.new(name: 'Amazing Place') @@ -30,6 +30,7 @@ module ActiveModel @post_serializer = PostSerializer.new(@post) @author_serializer = AuthorSerializer.new(@author) @comment_serializer = CommentSerializer.new(@comment) + @blog_serializer = BlogSerializer.new(@blog) end def test_cache_definition @@ -56,9 +57,9 @@ module ActiveModel end def test_cache_options_definition - assert_equal({expires_in: 0.1}, @post_serializer.class._cache_options) - assert_equal(nil, @author_serializer.class._cache_options) - assert_equal({expires_in: 1.day}, @comment_serializer.class._cache_options) + assert_equal({expires_in: 0.1, skip_digest: true}, @post_serializer.class._cache_options) + assert_equal(nil, @blog_serializer.class._cache_options) + assert_equal({expires_in: 1.day, skip_digest: true}, @comment_serializer.class._cache_options) end def test_fragment_cache_definition @@ -115,6 +116,15 @@ module ActiveModel assert_equal({place: 'Nowhere'}, ActionController::Base.cache_store.fetch(@location.cache_key)) end + def test_uses_file_digest_in_cahe_key + blog = render_object_with_cache(@blog) + assert_equal(@blog_serializer.attributes, ActionController::Base.cache_store.fetch(@blog.cache_key_with_digest)) + end + + def _cache_digest_definition + assert_equal(::Model::FILE_DIGEST, @post_serializer.class._cache_digest) + end + private def render_object_with_cache(obj) serializer_class = ActiveModel::Serializer.serializer_for(obj)