diff options
author | Edouard CHIN <edouard.chin@shopify.com> | 2019-07-11 16:25:40 +0200 |
---|---|---|
committer | Edouard CHIN <edouard.chin@shopify.com> | 2019-07-11 16:35:14 +0200 |
commit | f08bf726d3038f062dd7485614d1ea85d952f121 (patch) | |
tree | 527bfa072f66a4e5846b4dd2b099056ce029bfd6 /activesupport | |
parent | 84ff4f6ea2a118b47160e3fe7ed29bff52c2a7a2 (diff) | |
download | rails-f08bf726d3038f062dd7485614d1ea85d952f121.tar.gz rails-f08bf726d3038f062dd7485614d1ea85d952f121.tar.bz2 rails-f08bf726d3038f062dd7485614d1ea85d952f121.zip |
Return a copy of the cache entry when local_cache exists:
- When the local cache exists (during the request lifecycle), the
entry returned from the LocalStore is passed as a reference which
means mutable object can accidentaly get modified.
This behaviour seems unnecessarily unsafe and is prone to
issues like it happened in our application.
This patch dup the `Entry` returned from the cache and dup it's
internal value.
Diffstat (limited to 'activesupport')
-rw-r--r-- | activesupport/lib/active_support/cache/strategy/local_cache.rb | 5 | ||||
-rw-r--r-- | activesupport/test/cache/behaviors/local_cache_behavior.rb | 9 |
2 files changed, 13 insertions, 1 deletions
diff --git a/activesupport/lib/active_support/cache/strategy/local_cache.rb b/activesupport/lib/active_support/cache/strategy/local_cache.rb index 39b32fc7f6..4ca084163b 100644 --- a/activesupport/lib/active_support/cache/strategy/local_cache.rb +++ b/activesupport/lib/active_support/cache/strategy/local_cache.rb @@ -75,7 +75,10 @@ module ActiveSupport end def fetch_entry(key, options = nil) # :nodoc: - @data.fetch(key) { @data[key] = yield } + entry = @data.fetch(key) { @data[key] = yield } + dup_entry = entry.dup + dup_entry&.dup_value! + dup_entry end end diff --git a/activesupport/test/cache/behaviors/local_cache_behavior.rb b/activesupport/test/cache/behaviors/local_cache_behavior.rb index baa38ba6ac..6f5d53c190 100644 --- a/activesupport/test/cache/behaviors/local_cache_behavior.rb +++ b/activesupport/test/cache/behaviors/local_cache_behavior.rb @@ -46,6 +46,15 @@ module LocalCacheBehavior end end + def test_local_cache_of_read_returns_a_copy_of_the_entry + @cache.with_local_cache do + @cache.write(:foo, type: "bar") + value = @cache.read(:foo) + assert_equal("bar", value.delete(:type)) + assert_equal({ type: "bar" }, @cache.read(:foo)) + end + end + def test_local_cache_of_read @cache.write("foo", "bar") @cache.with_local_cache do |