Skip to content

Commit ad7e73f

Browse files
committed
Send Cache-Control: no-store on account and user-edit pages. OP-19674
Firefox serves these pages stale from the HTTP cache / bfcache on reload and history-back; the Turbo meta only covers Turbo's own snapshot. no-store opts out of both, fixing Firefox. Chrome revalidates and is already fresh on reload and forward navigation, so those two examples pass there and act as cross-browser guards.
1 parent 59c599e commit ad7e73f

4 files changed

Lines changed: 29 additions & 0 deletions

File tree

app/controllers/application_controller.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,13 @@ def set_cache_buster
178178
end
179179
end
180180

181+
# Firefox serves these pages stale from the HTTP cache and bfcache on reload and
182+
# history-back (the turbo-cache-control meta only governs Turbo's snapshot).
183+
# no-store opts out of both so a fresh copy is always fetched.
184+
def prevent_response_caching
185+
response.cache_control.merge!(no_store: true)
186+
end
187+
181188
def tag_request
182189
context = { controller: self, request: }
183190
::OpenProject::Appsignal.tag_request(context)

app/controllers/my_controller.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ class MyController < ApplicationController
4141
before_action :require_login
4242
before_action :set_current_user
4343
before_action :check_password_confirmation, only: %i[update_account]
44+
before_action :prevent_response_caching, only: :account
4445

4546
no_authorization_required! :account,
4647
:update_account,

app/controllers/users_controller.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ class UsersController < ApplicationController
3636
layout "admin"
3737

3838
before_action :authorize_global, except: %i[show deletion_info destroy]
39+
before_action :prevent_response_caching, only: :edit
3940

4041
# rubocop:disable Rails/LexicallyScopedActionFilter
4142
before_action :find_user, only: %i[show

spec/features/my/account_fresh_after_out_of_band_change_spec.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,24 @@ def expect_fresh_account
4242

4343
expect_fresh_account
4444
end
45+
46+
# Green in Chrome (it revalidates on reload) but stale in Firefox, where the HTTP
47+
# cache / bfcache serves the old page; fixed by `Cache-Control: no-store`.
48+
it "is fresh after a reload" do
49+
page.refresh
50+
51+
expect_fresh_account
52+
end
53+
54+
# Navigating back to the account page through the menu is a fresh Turbo visit;
55+
# this guards that it keeps fetching current data.
56+
it "is fresh after navigating away and back via the menu" do
57+
click_on "Notification and email"
58+
expect(page).to have_current_path(my_notifications_path, wait: 10, ignore_query: true)
59+
60+
click_on "Account"
61+
expect(page).to have_current_path(my_account_path, wait: 10, ignore_query: true)
62+
63+
expect_fresh_account
64+
end
4565
end

0 commit comments

Comments
 (0)