Module: Sinatra::Inertia::Helpers
- Defined in:
- lib/sinatra/inertia/helpers.rb
Overview
Sinatra helpers exposed to route handlers. Mounted by the ‘Sinatra::Inertia` extension.
Instance Method Summary collapse
- #always(value = nil, &block) ⇒ Object
- #clear_history! ⇒ Object
-
#csrf_token ⇒ Object
CSRF token for the current request.
-
#current_inertia_shared ⇒ Object
—————————————————————— Shared props — runtime accessors (the ‘inertia_share` class DSL is in extension.rb, this is the per-request resolver).
-
#current_inertia_version ⇒ Object
—————————————————————— Asset version.
- #defer(group: "default", &block) ⇒ Object
- #encrypt_history!(flag = true) ⇒ Object
-
#inertia(component, props: {}, layout: nil) ⇒ Object
Render an Inertia response.
- #inertia_clear_history! ⇒ Object
- #inertia_encrypt_history!(flag = true) ⇒ Object
-
#inertia_errors(payload = nil) ⇒ Object
—————————————————————— Errors / flash session sweep (per Inertia validation pattern).
- #inertia_errors_payload ⇒ Object
- #inertia_request? ⇒ Boolean
- #lazy(&block) ⇒ Object
- #merge(value = nil, &block) ⇒ Object
- #optional(&block) ⇒ Object
- #page_errors(payload = nil) ⇒ Object
- #page_request? ⇒ Boolean
-
#render(*args, **kwargs, &block) ⇒ Object
Natural page-rendering API: ‘render ’Component’, props_hash`.
- #sweep_inertia_session! ⇒ Object
Instance Method Details
#always(value = nil, &block) ⇒ Object
130 131 132 |
# File 'lib/sinatra/inertia/helpers.rb', line 130 def always(value = nil, &block) Sinatra::Inertia.always(value, &block) end |
#clear_history! ⇒ Object
198 199 200 |
# File 'lib/sinatra/inertia/helpers.rb', line 198 def clear_history! inertia_clear_history! end |
#csrf_token ⇒ Object
CSRF token for the current request. Mounted by CSRFMiddleware (‘set :inertia_csrf_protection, true` by default). Pair this with `inertia_share { { csrfToken: csrf_token } }` so the React/Vue client picks it up automatically — but note that when `Sinatra::Inertia::CSRFMiddleware` is active, the cookie + header exchange is already handled by the Inertia client; this helper is mainly for hidden-field forms or non-XHR submissions.
126 127 128 |
# File 'lib/sinatra/inertia/helpers.rb', line 126 def csrf_token request.env["sinatra.inertia.csrf_token"] end |
#current_inertia_shared ⇒ Object
Shared props — runtime accessors (the ‘inertia_share` class DSL is in extension.rb, this is the per-request resolver).
153 154 155 156 157 158 159 160 161 162 |
# File 'lib/sinatra/inertia/helpers.rb', line 153 def current_inertia_shared blocks = settings.inertia_share_blocks || [] merged = {} blocks.each do |b| v = instance_exec(&b) merged = deep_merge(merged, v) if v.is_a?(Hash) end merged end |
#current_inertia_version ⇒ Object
Asset version
166 167 168 169 170 171 172 173 174 |
# File 'lib/sinatra/inertia/helpers.rb', line 166 def current_inertia_version v = if settings.respond_to?(:page_version) settings.page_version elsif settings.respond_to?(:inertia_version) settings.inertia_version end v.respond_to?(:call) ? v.call.to_s : v.to_s end |
#defer(group: "default", &block) ⇒ Object
134 135 136 |
# File 'lib/sinatra/inertia/helpers.rb', line 134 def defer(group: "default", &block) Sinatra::Inertia.defer(group: group, &block) end |
#encrypt_history!(flag = true) ⇒ Object
206 207 208 |
# File 'lib/sinatra/inertia/helpers.rb', line 206 def encrypt_history!(flag = true) inertia_encrypt_history!(flag) end |
#inertia(component, props: {}, layout: nil) ⇒ Object
Render an Inertia response.
render 'Todos/Index', todos: -> { Todo.all }
Layout selection: the configured layout (default ‘:layout`) is rendered for full HTML responses. The view receives `@page_json` (an HTML-escaped JSON string ready to drop into a `data-page` attribute) and `@page` (the underlying Hash, useful for SSR or custom rendering).
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
# File 'lib/sinatra/inertia/helpers.rb', line 21 def inertia(component, props: {}, layout: nil) layout = current_page_layout if layout.nil? version = current_inertia_version shared = current_inertia_shared encrypt = if !@inertia_encrypt_history_override.nil? @inertia_encrypt_history_override == true elsif settings.respond_to?(:inertia_encrypt_history) settings.inertia_encrypt_history == true else false end clear = @inertia_clear_history == true # Set the protocol response headers BEFORE we touch any async # `to_h` resolution. Under Opal, `Response#to_h` is an `async` # function (it `await`s any Proc-returned JS Promise), so the # rest of this method runs after a JS-level suspend. Setting # `content_type` / `X-Inertia` before the suspend guarantees # Sinatra's dispatch sees them when it finalises the response, # regardless of how the underlying runtime schedules the # awaited continuation. if inertia_request? content_type("application/json; charset=utf-8") headers("X-Inertia" => "true", "Vary" => "X-Inertia") end # Read errors *before* sweeping so the response carries them, then # sweep immediately so the next request sees a clean slate. The # sweep must happen before any further session writes that the # framework might serialise on commit. errors_payload = inertia_errors_payload sweep_inertia_session! response_obj = Sinatra::Inertia::Response.new( component: component, props: props, request: request, version: version, url: request.fullpath, encrypt_history: encrypt, clear_history: clear, shared: shared, errors: errors_payload ) page_hash = response_obj.to_h page_json = page_hash.to_json return page_json if inertia_request? @page = page_hash @page_json = ::Rack::Utils.escape_html(page_json) erb(layout, layout: false) end |
#inertia_clear_history! ⇒ Object
194 195 196 |
# File 'lib/sinatra/inertia/helpers.rb', line 194 def inertia_clear_history! @inertia_clear_history = true end |
#inertia_encrypt_history!(flag = true) ⇒ Object
202 203 204 |
# File 'lib/sinatra/inertia/helpers.rb', line 202 def inertia_encrypt_history!(flag = true) @inertia_encrypt_history_override = flag end |
#inertia_errors(payload = nil) ⇒ Object
Errors / flash session sweep (per Inertia validation pattern). Consumers call ‘inertia_errors(field: ’message’)‘ before redirecting to a form route; the next request renders the form with errors and sweeps them out of the session.
181 182 183 184 185 186 187 188 |
# File 'lib/sinatra/inertia/helpers.rb', line 181 def inertia_errors(payload = nil) if payload.nil? (session[:_inertia_errors] || {}).dup else session[:_inertia_errors] = payload payload end end |
#inertia_errors_payload ⇒ Object
210 211 212 213 214 215 |
# File 'lib/sinatra/inertia/helpers.rb', line 210 def inertia_errors_payload errors = session[:_inertia_errors] return nil if errors.nil? return nil if errors.respond_to?(:empty?) && errors.empty? errors end |
#inertia_request? ⇒ Boolean
111 112 113 |
# File 'lib/sinatra/inertia/helpers.rb', line 111 def inertia_request? request.env["HTTP_X_INERTIA"] == "true" end |
#lazy(&block) ⇒ Object
142 143 144 |
# File 'lib/sinatra/inertia/helpers.rb', line 142 def lazy(&block) Sinatra::Inertia.lazy(&block) end |
#merge(value = nil, &block) ⇒ Object
146 147 148 |
# File 'lib/sinatra/inertia/helpers.rb', line 146 def merge(value = nil, &block) Sinatra::Inertia.merge(value, &block) end |
#optional(&block) ⇒ Object
138 139 140 |
# File 'lib/sinatra/inertia/helpers.rb', line 138 def optional(&block) Sinatra::Inertia.optional(&block) end |
#page_errors(payload = nil) ⇒ Object
190 191 192 |
# File 'lib/sinatra/inertia/helpers.rb', line 190 def page_errors(payload = nil) inertia_errors(payload) end |
#page_request? ⇒ Boolean
115 116 117 |
# File 'lib/sinatra/inertia/helpers.rb', line 115 def page_request? inertia_request? end |
#render(*args, **kwargs, &block) ⇒ Object
Natural page-rendering API: ‘render ’Component’, props_hash`. ‘render inertia: ’Component’, props: …‘ remains available for existing apps, while non-page render calls still delegate to Sinatra. We must preserve Sinatra’s ‘render(engine, data = nil, options = {}, locals = {}, &block)` signature for the non-inertia path, so we forward *args/**kwargs.
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/sinatra/inertia/helpers.rb', line 82 def render(*args, **kwargs, &block) first = args.first if args.length == 1 && first.is_a?(Hash) && first.key?(:inertia) inertia( first[:inertia], props: first[:props] || {}, layout: first[:layout] ) elsif kwargs.key?(:inertia) && args.empty? inertia( kwargs[:inertia], props: kwargs[:props] || {}, layout: kwargs[:layout] ) elsif first.is_a?(String) && args.length <= 2 && (args.length == 1 || args[1].is_a?(Hash)) layout = kwargs.delete(:layout) props = {} props.merge!(args[1]) if args[1].is_a?(Hash) explicit_props = kwargs.delete(:props) props.merge!(explicit_props) if explicit_props.is_a?(Hash) props.merge!(kwargs) inertia(first, props: props, layout: layout) else super(*args, **kwargs, &block) end end |
#sweep_inertia_session! ⇒ Object
217 218 219 220 221 222 223 224 225 226 |
# File 'lib/sinatra/inertia/helpers.rb', line 217 def sweep_inertia_session! # Rack::Session::Cookie tracks writes by hash mutation. On some # session backends (e.g. the JSON-coder cookie store homura uses # under Cloudflare Workers) `delete` is a no-op for the *backing # cookie* — the change isn't serialised back. Force a write by # assigning nil instead, which the JSON encoder still emits as # `null` and makes `inertia_errors_payload` treat the field as # absent on the next visit. session[:_inertia_errors] = nil if session.respond_to?(:[]=) end |