aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/integration.rb
diff options
context:
space:
mode:
authorDavid Heinemeier Hansson <david@loudthinking.com>2017-05-18 18:12:32 +0200
committerGitHub <noreply@github.com>2017-05-18 18:12:32 +0200
commit75fa8dd309a84e125b59d01bf182d88419631eaa (patch)
treed76aa54a79b7bf07d6e6c5d3f6c07237e5f4af60 /activerecord/lib/active_record/integration.rb
parent385d9af299fbfac7f063de214d371545bafef5df (diff)
downloadrails-75fa8dd309a84e125b59d01bf182d88419631eaa.tar.gz
rails-75fa8dd309a84e125b59d01bf182d88419631eaa.tar.bz2
rails-75fa8dd309a84e125b59d01bf182d88419631eaa.zip
Use recyclable cache keys (#29092)
Diffstat (limited to 'activerecord/lib/active_record/integration.rb')
-rw-r--r--activerecord/lib/active_record/integration.rb49
1 files changed, 40 insertions, 9 deletions
diff --git a/activerecord/lib/active_record/integration.rb b/activerecord/lib/active_record/integration.rb
index 8e71b60b29..ed652e26aa 100644
--- a/activerecord/lib/active_record/integration.rb
+++ b/activerecord/lib/active_record/integration.rb
@@ -13,6 +13,15 @@ module ActiveRecord
# This is +:usec+, by default.
class_attribute :cache_timestamp_format, instance_writer: false
self.cache_timestamp_format = :usec
+
+ ##
+ # :singleton-method:
+ # Indicates whether to use a stable #cache_key method that is accompanied
+ # by a changing version in the #cache_version method.
+ #
+ # This is +false+, by default until Rails 6.0.
+ class_attribute :cache_versioning, instance_writer: false
+ self.cache_versioning = false
end
# Returns a +String+, which Action Pack uses for constructing a URL to this
@@ -52,25 +61,47 @@ module ActiveRecord
# 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"
else
- timestamp = if timestamp_names.any?
- max_updated_column_timestamp(timestamp_names)
+ if cache_version && timestamp_names.none?
+ "#{model_name.cache_key}/#{id}"
else
- max_updated_column_timestamp
- end
+ timestamp = if timestamp_names.any?
+ max_updated_column_timestamp(timestamp_names)
+ else
+ max_updated_column_timestamp
+ end
- if timestamp
- timestamp = timestamp.utc.to_s(cache_timestamp_format)
- "#{model_name.cache_key}/#{id}-#{timestamp}"
- else
- "#{model_name.cache_key}/#{id}"
+ if timestamp
+ timestamp = timestamp.utc.to_s(cache_timestamp_format)
+ "#{model_name.cache_key}/#{id}-#{timestamp}"
+ else
+ "#{model_name.cache_key}/#{id}"
+ end
end
end
end
+ # Returns a cache version that can be used together with the cache key to form
+ # a recyclable caching scheme. By default, the #updated_at column is used for the
+ # cache_version, but this method can be overwritten to return something else.
+ #
+ # 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
+ end
+
module ClassMethods
# Defines your model's +to_param+ method to generate "pretty" URLs
# using +method_name+, which can be any attribute or method that