ruby erb javascript 96 lines · 4 tabs

Avoid caching sensitive pages in Turbo Drive

Shared by codesnips Jan 2026
4 tabs
class ApplicationController < ActionController::Base
  before_action :set_turbo_cache_control

  class_attribute :turbo_no_cache, default: false

  def self.no_turbo_cache
    self.turbo_no_cache = true
  end

  private

  def set_turbo_cache_control
    return unless self.class.turbo_no_cache

    @turbo_cache_control = "no-cache"
    response.headers["Cache-Control"] = "no-store, no-cache, must-revalidate, private"
    response.headers["Pragma"] = "no-cache"
  end
end
4 files · ruby, erb, javascript Explain with highlit

Turbo Drive keeps a client-side cache of visited pages so that back/forward navigation and restoration renders feel instant. It shows a cached snapshot immediately, then fetches a fresh copy in the background. That behavior is great for public pages but dangerous for authenticated ones: after a user logs out, pressing Back can flash the previous user's account page from the in-memory snapshot cache, leaking data on shared machines. This snippet shows the two coordinated defenses needed to fully suppress that.

The ApplicationController sets an explicit opt-out on every response that renders sensitive data. set_turbo_cache_control inspects a class-level turbo_no_cache flag and, when present, emits <meta name="turbo-cache-control" content="no-cache"> via a helper-populated @turbo_cache_control and also sends HTTP Cache-Control: no-store headers. The no_turbo_cache macro lets individual controllers declare themselves non-cacheable, which is why AccountsController calls it at the top. The turbo-cache-control meta tag is the canonical Turbo mechanism: no-cache tells Turbo to skip showing a preview snapshot for this page, so a stale render never appears even briefly.

The layout in application.html.erb renders @turbo_cache_control into the document head only when set. Turbo reads this meta tag on each navigation, so it must be present in the served HTML rather than injected later.

The meta tag alone is not enough, because Turbo may have already cached earlier snapshots before logout. The logout controller Stimulus controller calls Turbo.cache.clear() on beforeCache and immediately when logout is triggered, wiping every stored snapshot. Turbo.session.clearCache() is invoked defensively as well. Wiring it to the sign-out button guarantees the cache is emptied at the exact moment the session ends.

A key trade-off is that no-cache disables the instant-preview optimization for those pages, so navigation feels slightly slower — an acceptable cost for account, billing, or admin screens. The pitfall to avoid is relying only on HTTP headers: Turbo's snapshot cache lives in memory and ignores Cache-Control, which is why the meta tag and explicit clear() are both required. Reach for this pattern on any route rendering per-user data behind authentication.


Related snips

Share this code

Here's the card — post it anywhere.

Avoid caching sensitive pages in Turbo Drive — share card
Link copied