diff --git a/lib/active_model/serializer.rb b/lib/active_model/serializer.rb index 4083c96bc..48af6e7c4 100644 --- a/lib/active_model/serializer.rb +++ b/lib/active_model/serializer.rb @@ -29,6 +29,20 @@ class Serializer ) /x + # Hashes contents of file for +_cache_digest+ + def self.digest_caller_file(caller_line) + serializer_file_path = caller_line[CALLER_FILE] + serializer_file_contents = IO.read(serializer_file_path) + Digest::MD5.hexdigest(serializer_file_contents) + rescue TypeError, Errno::ENOENT + warn <<-EOF.strip_heredoc + Cannot digest non-existent file: '#{caller_line}'. + Please set `::_cache_digest` of the serializer + if you'd like to cache it. + EOF + ''.freeze + end + class << self attr_accessor :_attributes # @api private : names of attribute methods, @see Serializer#attribute attr_accessor :_attributes_keys # @api private : maps attribute value to explict key name, @see Serializer#attribute @@ -54,9 +68,10 @@ class << self # Serializers inherit _attributes and _attributes_keys. # Generates a unique digest for each serializer at load. def self.inherited(base) + caller_line = caller.first base._attributes = _attributes.try(:dup) || [] base._attributes_keys = _attributes_keys.try(:dup) || {} - base._cache_digest = digest_caller_file(caller.first) + base._cache_digest = digest_caller_file(caller_line) super end @@ -163,13 +178,6 @@ def self.serializers_cache @serializers_cache ||= ThreadSafe::Cache.new end - # Hashes contents of file for +_cache_digest+ - def self.digest_caller_file(caller_line) - serializer_file_path = caller_line[CALLER_FILE] - serializer_file_contents = IO.read(serializer_file_path) - Digest::MD5.hexdigest(serializer_file_contents) - end - # Find a serializer from a class and caches the lookup. # Preferentially retuns: # 1. class name appended with "Serializer" diff --git a/test/serializers/cache_test.rb b/test/serializers/cache_test.rb index 374e1f61c..284c7b2ea 100644 --- a/test/serializers/cache_test.rb +++ b/test/serializers/cache_test.rb @@ -3,6 +3,8 @@ module ActiveModel class Serializer class CacheTest < Minitest::Test + include ActiveSupport::Testing::Stream + def setup ActionController::Base.cache_store.clear @comment = Comment.new(id: 1, body: 'ZOMG A COMMENT') @@ -170,6 +172,16 @@ def test_digest_caller_file file.unlink end + def test_warn_on_serializer_not_defined_in_file + called = false + serializer = Class.new(ActiveModel::Serializer) + assert_match(/_cache_digest/, (capture(:stderr) do + serializer.digest_caller_file('') + called = true + end)) + assert called + end + private def render_object_with_cache(obj)