mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Add cache_key_with_version and use it in ActiveSupport::Cache.expand_cache_key
This retains the existing behavior of ActiveSupport::Cache.expand_cache_key (as used by etaging) where the cache key includes the version.
This commit is contained in:
parent
f8b5b4af84
commit
aa8749eb52
4 changed files with 51 additions and 29 deletions
|
@ -7,8 +7,8 @@ module ActiveRecord
|
|||
included do
|
||||
##
|
||||
# :singleton-method:
|
||||
# Indicates the format used to generate the timestamp in the cache key.
|
||||
# Accepts any of the symbols in <tt>Time::DATE_FORMATS</tt>.
|
||||
# Indicates the format used to generate the timestamp in the cache key, if
|
||||
# versioning is off. Accepts any of the symbols in <tt>Time::DATE_FORMATS</tt>.
|
||||
#
|
||||
# This is +:usec+, by default.
|
||||
class_attribute :cache_timestamp_format, instance_writer: false
|
||||
|
@ -51,24 +51,16 @@ module ActiveRecord
|
|||
id && id.to_s # Be sure to stringify the id for routes
|
||||
end
|
||||
|
||||
# Returns a cache key that can be used to identify this record.
|
||||
# Returns a stable cache key that can be used to identify this record.
|
||||
#
|
||||
# Product.new.cache_key # => "products/new"
|
||||
# Product.find(5).cache_key # => "products/5" (updated_at not available)
|
||||
# Product.find(5).cache_key # => "products/5"
|
||||
#
|
||||
# If ActiveRecord::Base.cache_versioning is turned off, as it was in Rails 5.1 and earlier,
|
||||
# the cache key will also include a version.
|
||||
#
|
||||
# Product.cache_versioning = false
|
||||
# Person.find(5).cache_key # => "people/5-20071224150000" (updated_at available)
|
||||
#
|
||||
# You can also pass a list of named timestamps, and the newest in the list will be
|
||||
# used to generate the key:
|
||||
#
|
||||
# Person.find(5).cache_key(:updated_at, :last_reviewed_at)
|
||||
#
|
||||
# If ActiveRecord::Base.cache_versioning is turned on, no version will be included
|
||||
# in the cache key. The version will instead be supplied by #cache_version. This
|
||||
# separation enables recycling of cache keys.
|
||||
#
|
||||
# Product.cache_versioning = true
|
||||
# Product.new.cache_key # => "products/new"
|
||||
# Person.find(5).cache_key # => "people/5" (even if updated_at available)
|
||||
def cache_key(*timestamp_names)
|
||||
if new_record?
|
||||
"#{model_name.cache_key}/new"
|
||||
|
@ -77,6 +69,11 @@ module ActiveRecord
|
|||
"#{model_name.cache_key}/#{id}"
|
||||
else
|
||||
timestamp = if timestamp_names.any?
|
||||
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
||||
Specifying a timestamp name for #cache_key has been deprecated in favor of
|
||||
the explicit #cache_version method that can be overwritten.
|
||||
MSG
|
||||
|
||||
max_updated_column_timestamp(timestamp_names)
|
||||
else
|
||||
max_updated_column_timestamp
|
||||
|
@ -99,8 +96,20 @@ module ActiveRecord
|
|||
# Note, this method will return nil if ActiveRecord::Base.cache_versioning is set to
|
||||
# +false+ (which it is by default until Rails 6.0).
|
||||
def cache_version
|
||||
try(:updated_at).try(:to_i) if cache_versioning
|
||||
if cache_versioning && timestamp = try(:updated_at)
|
||||
updated_at.utc.to_s(:usec)
|
||||
end
|
||||
end
|
||||
|
||||
# Returns a cache key along with the version.
|
||||
def cache_key_with_version
|
||||
if version = cache_version
|
||||
"#{cache_key}-#{version}"
|
||||
else
|
||||
cache_key
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
module ClassMethods
|
||||
# Defines your model's +to_param+ method to generate "pretty" URLs
|
||||
|
|
|
@ -39,5 +39,13 @@ module ActiveRecord
|
|||
assert CacheMeWithVersion.create.cache_version.present?
|
||||
assert_not CacheMe.create.cache_version.present?
|
||||
end
|
||||
|
||||
test "cache_key_with_version always has both key and version" do
|
||||
r1 = CacheMeWithVersion.create
|
||||
assert_equal "active_record/cache_key_test/cache_me_with_versions/#{r1.id}-#{r1.updated_at.to_s(:usec)}", r1.cache_key_with_version
|
||||
|
||||
r2 = CacheMe.create
|
||||
assert_equal "active_record/cache_key_test/cache_mes/#{r2.id}-#{r2.updated_at.to_s(:usec)}", r2.cache_key_with_version
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -168,15 +168,19 @@ class IntegrationTest < ActiveRecord::TestCase
|
|||
end
|
||||
|
||||
def test_named_timestamps_for_cache_key
|
||||
assert_deprecated do
|
||||
owner = owners(:blackbeard)
|
||||
assert_equal "owners/#{owner.id}-#{owner.happy_at.utc.to_s(:usec)}", owner.cache_key(:updated_at, :happy_at)
|
||||
end
|
||||
end
|
||||
|
||||
def test_cache_key_when_named_timestamp_is_nil
|
||||
assert_deprecated do
|
||||
owner = owners(:blackbeard)
|
||||
owner.happy_at = nil
|
||||
assert_equal "owners/#{owner.id}", owner.cache_key(:happy_at)
|
||||
end
|
||||
end
|
||||
|
||||
def test_cache_key_is_stable_with_versioning_on
|
||||
Developer.cache_versioning = true
|
||||
|
@ -213,13 +217,13 @@ class IntegrationTest < ActiveRecord::TestCase
|
|||
Developer.cache_versioning = true
|
||||
|
||||
developer = Developer.first
|
||||
first_key = developer.cache_key(:updated_at)
|
||||
first_key = developer.cache_key_with_version
|
||||
|
||||
travel 10.seconds do
|
||||
developer.touch
|
||||
end
|
||||
|
||||
second_key = developer.cache_key(:updated_at)
|
||||
second_key = developer.cache_key_with_version
|
||||
|
||||
assert_not_equal first_key, second_key
|
||||
ensure
|
||||
|
|
|
@ -88,6 +88,7 @@ module ActiveSupport
|
|||
private
|
||||
def retrieve_cache_key(key)
|
||||
case
|
||||
when key.respond_to?(:cache_key_with_version) then key.cache_key_with_version
|
||||
when key.respond_to?(:cache_key) then key.cache_key
|
||||
when key.is_a?(Array) then key.map { |element| retrieve_cache_key(element) }.to_param
|
||||
when key.respond_to?(:to_a) then retrieve_cache_key(key.to_a)
|
||||
|
|
Loading…
Reference in a new issue