ruby erb javascript 76 lines · 3 tabs

Turbo Drive: disable caching on volatile admin pages

Shared by codesnips Jan 2026
3 tabs
class AdminController < ApplicationController
  before_action :authenticate_admin!
  before_action :disable_turbo_cache, only: %i[dashboard moderation_queue]

  helper_method :turbo_cache_control_tag

  def dashboard
    @pending_payouts = Payout.pending.sum(:amount_cents)
    @open_reports = Report.open.count
  end

  def moderation_queue
    @flags = Flag.unresolved.order(created_at: :asc).limit(50)
  end

  private

  def disable_turbo_cache
    @turbo_no_cache = true
  end

  def turbo_cache_control_tag
    return unless @turbo_no_cache

    tag.meta(name: "turbo-cache-control", content: "no-preview")
  end
end
3 files · ruby, erb, javascript Explain with highlit

Turbo Drive keeps a snapshot cache of visited pages and, on navigation, briefly renders a stale preview of a page before swapping in the fresh network response. On mostly-static pages this makes navigation feel instant, but on volatile admin dashboards — live queues, balances, moderation counts — the preview shows numbers that are already wrong, which reads as a bug. The fix is to opt those specific pages out of caching rather than disabling Turbo globally.

The AdminController tab centers the mechanism on a per-request flag. disable_turbo_cache sets @turbo_no_cache = true and is invoked from a before_action on the volatile actions, while a helper method turbo_cache_control_tag (exposed with helper_method) emits the correct <meta name="turbo-cache-control"> tag. Turbo recognizes three values: no-cache lets the page be restored from cache but never serves it as a preview, and no-preview is the stronger form that prevents the stale flash entirely — the dashboard uses no-preview so admins never see outdated figures.

The admin layout tab renders that tag inside <head> via yielding the helper, so the directive lands in the exact place Turbo reads it during a snapshot. Because the meta tag is evaluated per response, the same layout serves both cached and uncached pages depending on the controller flag; there is no separate template.

The turbo_cache_controller tab handles the harder case: pages cached before the flag existed, or fragments that mutate after load. It calls Turbo.cache.exemptPageFromCache() on turbo:load so the current page is never stored, and clears the whole snapshot cache on turbo:before-cache when the element carries a reset value. This is a Stimulus controller wired through importmap, giving fine-grained, element-level control without a full page directive.

The trade-off is real: opting out of preview caching costs the instant-render feel and forces a visible network wait, so it should be scoped narrowly to genuinely volatile views. A common pitfall is disabling caching site-wide, which quietly removes one of Turbo's main performance wins for pages that never needed it.


Related snips

ruby
class CommentsController < ApplicationController
  before_action :set_post

  def create
    @comment = @post.comments.build(comment_params)

System test: asserting Turbo Stream responses

rails hotwire turbo
by codesnips 4 tabs
ruby
class Post < ApplicationRecord
  belongs_to :author, class_name: 'User'
  has_many :comments, dependent: :destroy

  scope :published, -> { where.not(published_at: nil).where('published_at <= ?', Time.current) }
  scope :draft, -> { where(published_at: nil) }

ActiveRecord scopes for reusable query logic

rails activerecord patterns
by Alex Kumar 1 tab
ruby
module Api
  module V1
    class UsersController < BaseController
      def show
        user = User.includes(:profile).find(params[:id])

ETags for conditional requests and caching

rails caching http-caching
by Alex Kumar 1 tab
ruby
class PostsController < ApplicationController
  def index
    @posts = Post.includes(:author)
                 .order(created_at: :desc)
                 .page(params[:page])
                 .per(10)

Turbo Frames: infinite scroll with lazy-loading frame

rails turbo hotwire
by codesnips 4 tabs
ruby
require "csv"

class PeopleCsvStream
  include Enumerable

  HEADERS = %w[id full_name email signed_up_at plan].freeze

Resilient CSV Export as a Streamed Response

rails performance streaming
by codesnips 3 tabs
erb
<form data-controller="query-sync" data-action="change->query-sync#apply">
  <select name="status" class="rounded border p-2">
    <option value="">Any</option>
    <option value="open">Open</option>
    <option value="closed">Closed</option>
  </select>

Filter UI that syncs query params via Stimulus (no front-end router)

rails hotwire stimulus
by Henry Kim 2 tabs

Share this code

Here's the card — post it anywhere.

Turbo Drive: disable caching on volatile admin pages — share card
Link copied