1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Enforce fresh ETag header after collection changes

Add ActiveRecord::Relation#cache_key_with_version. This method will be
used by ActionController::ConditionalGet to ensure that when collection
cache versioning is enabled, requests using ConditionalGet don't return
the same ETag header after a collection is modified.

Prior to the introduction of collection cache versioning in
4f2ac80d4c, all collection cache keys
included a version. However, with cache versioning enabled, collection
cache keys remain constant. In turn, ETag headers remain constant,
rendering them ineffective.

This commit takes the cache_key_with_version method used for individual
Active Record objects (from aa8749eb52),
and adds it to collections.
This commit is contained in:
Aaron Lipman 2019-12-29 14:34:46 -05:00
parent b8dc13050c
commit 58b040964f
3 changed files with 27 additions and 0 deletions

View file

@ -1,3 +1,11 @@
* Enforce fresh ETag header after a collection's contents change by adding
ActiveRecord::Relation#cache_key_with_version. This method will be used by
ActionController::ConditionalGet to ensure that when collection cache versioning
is enabled, requests using ConditionalGet don't return the same ETag header
after a collection is modified. Fixes #38078.
*Aaron Lipman*
* Skip test database when running `db:create` or `db:drop` in development
with `DATABASE_URL` set.

View file

@ -385,6 +385,15 @@ module ActiveRecord
end
private :compute_cache_version
# 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
# Scope all queries to the current scope.
#
# Comment.where(post_id: 1).scoping do

View file

@ -198,6 +198,16 @@ module ActiveRecord
end
end
test "cache_key_with_version contains key and version regardless of collection_cache_versioning setting" do
key_with_version_1 = Developer.all.cache_key_with_version
assert_match(/\Adevelopers\/query-(\h+)-(\d+)-(\d+)\z/, key_with_version_1)
with_collection_cache_versioning do
key_with_version_2 = Developer.all.cache_key_with_version
assert_equal(key_with_version_1, key_with_version_2)
end
end
def with_collection_cache_versioning(value = true)
@old_collection_cache_versioning = ActiveRecord::Base.collection_cache_versioning
ActiveRecord::Base.collection_cache_versioning = value