Class: Phlex::Reactive::ActionsController
- Inherits:
-
Object
- Object
- Phlex::Reactive::ActionsController
- Defined in:
- app/controllers/phlex/reactive/actions_controller.rb
Overview
The single endpoint behind every reactive component. The generic
reactive Stimulus controller POSTs here with a signed identity token,
an action name, and params. We verify the token, rebuild the component
(re-finding the record from the DB for record-backed components), run the
whitelisted action, and return an auto-targeted Turbo Stream the client
morphs in.
Customizing in your app:
* Authentication — by default this inherits from
Phlex::Reactive.base_controller (ActionController::Base). Set it to
your ApplicationController to get current_user/Current/CSRF, but make
sure the action path isn't force-redirected for logged-out users if
you have public reactive components.
* Authorization — DO IT IN THE COMPONENT ACTION. The token proves the
identity is ours, not that this user may act. Raise from the action
(e.g. authorize!), and configure Phlex::Reactive.authorization_errors
so it's rendered as 403 here.
Instance Method Summary collapse
- #create ⇒ Object
-
#deferred ⇒ Object
The defer endpoint (issue #165) — the pull lane's render leg.
Instance Method Details
#create ⇒ Object
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'app/controllers/phlex/reactive/actions_controller.rb', line 29 def create # ONE action.phlex_reactive event per request (issue #107). The event # payload carries the component/action NAMES + outcome ONLY (never the # token, params, or state); we fill it as those become known and set # :outcome on every exit path — the success tail and each rescue. The # rescue bodies are unchanged (verbose diagnostics + reactive_error per # #82/#87); we only ADD the outcome finalizer. `action` is safe to read # up front (it comes from the request, not the verified token). event = { component: nil, action: reactive_action_name.to_s, outcome: nil } # Mint any reply.defer directive tokens UNDER the actor's binding (issue # #165 security), so the defer endpoint accepts them ONLY back from this # same actor. The defer token is built in response_streams (inside this # block via the Defer builder), so the binding must be established here. Phlex::Reactive.with_defer_binding(Phlex::Reactive.defer_binding_for(request)) do Phlex::Reactive.instrument("action", event) do create_action(event) end end end |
#deferred ⇒ Object
The defer endpoint (issue #165) — the pull lane's render leg. Verifies the purpose-scoped, short-TTL defer token (an ACTION token is rejected here by signature — purpose confusion fails closed), rebuilds the component from its signed identity, and returns its replace (or morph, per the SIGNED mode) stream. No action runs and no transaction opens — this is a read. Authorization: the base controller's auth applies as on every reactive request; a component that guards visibility can raise a registered authorization error from from_identity/render (→ 403) or return false from render? (→ 204: keep content, clear pending).
58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'app/controllers/phlex/reactive/actions_controller.rb', line 58 def deferred event = { component: nil, outcome: nil } # Verify UNDER the actor's binding (issue #165 security): a defer token # minted for another actor's session fails the binding-scoped purpose, # so a leaked token can't be exchanged here for this actor's render (and # its embedded fresh identity token). Unbound requests (no session) are # unchanged. Phlex::Reactive.with_defer_binding(Phlex::Reactive.defer_binding_for(request)) do Phlex::Reactive.instrument("defer", event) do deferred_action(event) end end end |