Module: Controllers::RequireTurboFrame

Overview

Guards frame-only controller actions from ever rendering as a bare,
layout-less full page.

Controllers that render Turbo Frame fragments typically use layout false.
If such an endpoint is reached as a top-level navigation instead of a
Turbo Frame request — the address bar, a bookmarked/shared link, a crawler,
or a Turbo frame-missing promotion — Rails would happily render the
fragment with no layout: a broken, unstyled page. (See the /navbar_account
report: the navbar mega menu occasionally full-page-loaded the bare account
login fragment.)

This concern redirects any non-Turbo-Frame request for the guarded actions
to a real, full-page destination instead.

Usage:
class NavbarAccountController < ApplicationController
include Controllers::RequireTurboFrame
require_turbo_frame only: :show,
fallback: -> { current_account ? my_account_path : root_path }
end

Class Method Summary collapse

Class Method Details

.require_in_pane_tab_frames(only:, host: :show) ⇒ void

This method returns an undefined value.

Convention wrapper for lazy-loaded tab fragment actions (tab_*, show_*):
any request that would render the fragment as a full page redirects to the
host page (default: this controller's #show) with ?tab= preselected. The
tab key is the action name minus its tab_/show_ prefix — the same
convention the client's turbo-tabs controller uses to map hrefs to tabs.

Parameters:

  • only (Array<Symbol>)

    the tab fragment actions to guard.

  • host (Symbol) (defaults to: :show)

    the action rendering the tab_panel host page.



66
67
68
69
70
71
72
# File 'app/concerns/controllers/require_turbo_frame.rb', line 66

def require_in_pane_tab_frames(only:, host: :show)
  require_turbo_frame only: only, in_pane: true, fallback: lambda {
    url_for(action: host,
            tab: action_name.delete_prefix('tab_').delete_prefix('show_'),
            content_locale: params[:content_locale].presence)
  }
end

.require_turbo_frame(fallback:, in_pane: false, **action_filter) ⇒ void

This method returns an undefined value.

Parameters:

  • fallback (Symbol, String, Proc)

    where to send a non-frame request.
    A Symbol is sent as a method (e.g. a path helper); a Proc is evaluated in
    controller instance context so it can branch on request state
    (current_account, params, …); a String is used verbatim.

  • in_pane (Boolean) (defaults to: false)

    when true, admit only requests that would render
    layoutless in-pane content (Turbo Frame fetches for this pane, XHR,
    turbo_stream) and redirect anything that would paint a full page —
    plain navigation AND breakout-classified frame fetches whose
    Turbo-Frame header names a different pane (see
    ApplicationController#tab_frame_breakout_request?). Use for tab_*
    fragment actions that must never stand alone as a page.

  • action_filter (Hash)

    forwarded to before_action (only: / except:).

Options Hash (**action_filter):

  • only (Array<Symbol>)

    restrict the guard to these actions

  • except (Array<Symbol>)

    exempt these actions from the guard



42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'app/concerns/controllers/require_turbo_frame.rb', line 42

def require_turbo_frame(fallback:, in_pane: false, **action_filter)
  before_action(**action_filter) do
    next if in_pane ? !should_render_layout? : turbo_frame_request?

    target =
      case fallback
      when Symbol then send(fallback)
      when Proc   then instance_exec(&fallback)
      else fallback
      end

    redirect_to target
  end
end