diff --git a/app/controllers/concerns/cached_responses.rb b/app/controllers/concerns/cached_responses.rb index 75f2444..a933a71 100644 --- a/app/controllers/concerns/cached_responses.rb +++ b/app/controllers/concerns/cached_responses.rb @@ -9,7 +9,14 @@ module CachedResponses end def perform_caching - super && @response_cache_version.present? && !ActiveRecord::Base.connection.transaction_open? + return false unless super && @response_cache_version.present? && !ActiveRecord::Base.connection.transaction_open? + + # Check again after authentication, before the first native fragment lookup. + # Later renders retain this immutable namespace and cannot poison a new epoch. + unless defined?(@fragment_cache_snapshot_valid) + @fragment_cache_snapshot_valid = @response_cache_version == ResponseCache.instance.version + end + @fragment_cache_snapshot_valid end # Keep the class store (including shared rate limits) and Rails.cache unchanged. diff --git a/test/controllers/fragment_cache_test.rb b/test/controllers/fragment_cache_test.rb index aa73b43..cd313ff 100644 --- a/test/controllers/fragment_cache_test.rb +++ b/test/controllers/fragment_cache_test.rb @@ -61,6 +61,19 @@ class FragmentRenderingTest < ActionDispatch::IntegrationTest assert_includes response.body, "foreign conditional body" end + test "a foreign commit after capture bypasses old native fragment lookups" do + ResponseCache.instance.stubs(:budget).returns(0) + get room_messages_url(@room) + assert_response :success + MessagesController.any_instance.stubs(:set_version_headers).with do + foreign_write("UPDATE action_text_rich_texts SET body = ? WHERE record_type = 'Message' AND record_id = ?", "foreign before fragments", @message.id) + true + end + get room_messages_url(@room), headers: { "If-None-Match" => "unmatched" } + assert_response :success + assert_includes response.body, "foreign before fragments" + end + test "refresh streams recheck native cached creator body and boost presentation" do message = messages(:first) room = message.room