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
118 119 120 |
# File 'lib/sinatra/inertia/helpers.rb', line 118 def always(value = nil, &block) Sinatra::Inertia.always(value, &block) end |
#clear_history! ⇒ Object
186 187 188 |
# File 'lib/sinatra/inertia/helpers.rb', line 186 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.
114 115 116 |
# File 'lib/sinatra/inertia/helpers.rb', line 114 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).
141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/sinatra/inertia/helpers.rb', line 141 def current_inertia_shared blocks = settings.inertia_share_blocks || [] merged = {} blocks.each do |b| v = instance_exec(&b) if v.is_a?(Hash) merged = deep_merge(merged, v) end end merged end |
#current_inertia_version ⇒ Object
Asset version
155 156 157 158 159 160 161 162 |
# File 'lib/sinatra/inertia/helpers.rb', line 155 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
122 123 124 |
# File 'lib/sinatra/inertia/helpers.rb', line 122 def defer(group: 'default', &block) Sinatra::Inertia.defer(group: group, &block) end |
#encrypt_history!(flag = true) ⇒ Object
194 195 196 |
# File 'lib/sinatra/inertia/helpers.rb', line 194 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).
20 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 |
# File 'lib/sinatra/inertia/helpers.rb', line 20 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
182 183 184 |
# File 'lib/sinatra/inertia/helpers.rb', line 182 def inertia_clear_history! @inertia_clear_history = true end |
#inertia_encrypt_history!(flag = true) ⇒ Object
190 191 192 |
# File 'lib/sinatra/inertia/helpers.rb', line 190 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.
169 170 171 172 173 174 175 176 |
# File 'lib/sinatra/inertia/helpers.rb', line 169 def inertia_errors(payload = nil) if payload.nil? (session[:_inertia_errors] || {}).dup else session[:_inertia_errors] = payload payload end end |
#inertia_errors_payload ⇒ Object
198 199 200 201 202 203 |
# File 'lib/sinatra/inertia/helpers.rb', line 198 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
99 100 101 |
# File 'lib/sinatra/inertia/helpers.rb', line 99 def inertia_request? request.env['HTTP_X_INERTIA'] == 'true' end |
#lazy(&block) ⇒ Object
130 131 132 |
# File 'lib/sinatra/inertia/helpers.rb', line 130 def lazy(&block) Sinatra::Inertia.lazy(&block) end |
#merge(value = nil, &block) ⇒ Object
134 135 136 |
# File 'lib/sinatra/inertia/helpers.rb', line 134 def merge(value = nil, &block) Sinatra::Inertia.merge(value, &block) end |
#optional(&block) ⇒ Object
126 127 128 |
# File 'lib/sinatra/inertia/helpers.rb', line 126 def optional(&block) Sinatra::Inertia.optional(&block) end |
#page_errors(payload = nil) ⇒ Object
178 179 180 |
# File 'lib/sinatra/inertia/helpers.rb', line 178 def page_errors(payload = nil) inertia_errors(payload) end |
#page_request? ⇒ Boolean
103 104 105 |
# File 'lib/sinatra/inertia/helpers.rb', line 103 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.
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 |
# File 'lib/sinatra/inertia/helpers.rb', line 80 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
205 206 207 208 209 210 211 212 213 214 215 216 |
# File 'lib/sinatra/inertia/helpers.rb', line 205 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. if session.respond_to?(:[]=) session[:_inertia_errors] = nil end end |