inertia_rails 3.10.0 → 3.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/app/controllers/inertia_rails/static_controller.rb +5 -1
- data/lib/generators/inertia/install/frameworks.yml +5 -1
- data/lib/generators/inertia/install/install_generator.rb +8 -3
- data/lib/generators/inertia/install/templates/initializer.rb +2 -1
- data/lib/generators/inertia/install/templates/svelte/inertia.js +0 -5
- data/lib/generators/inertia/install/templates/svelte/inertia.ts.tt +1 -6
- data/lib/inertia_rails/action_filter.rb +2 -1
- data/lib/inertia_rails/configuration.rb +11 -1
- data/lib/inertia_rails/controller.rb +32 -12
- data/lib/inertia_rails/defer_prop.rb +5 -16
- data/lib/inertia_rails/engine.rb +6 -4
- data/lib/inertia_rails/helper.rb +26 -22
- data/lib/inertia_rails/inertia_rails.rb +8 -2
- data/lib/inertia_rails/lazy_prop.rb +1 -1
- data/lib/inertia_rails/merge_prop.rb +3 -12
- data/lib/inertia_rails/prop_mergeable.rb +83 -0
- data/lib/inertia_rails/renderer.rb +93 -24
- data/lib/inertia_rails/rspec.rb +28 -19
- data/lib/inertia_rails/scroll_metadata.rb +97 -0
- data/lib/inertia_rails/scroll_prop.rb +35 -0
- data/lib/inertia_rails/version.rb +3 -1
- data/lib/patches/better_errors.rb +4 -4
- data/lib/patches/debug_exceptions.rb +27 -10
- data/lib/patches/mapper.rb +6 -1
- data/lib/patches/request.rb +2 -0
- data/lib/tasks/inertia_rails.rake +7 -5
- metadata +6 -8
- data/lib/patches/debug_exceptions/patch-5-0.rb +0 -27
- data/lib/patches/debug_exceptions/patch-5-1.rb +0 -30
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 95b5901a42397a1ae01678a1101d5d21a6a2f2f33c6afb413a2fbca48f04e064
|
|
4
|
+
data.tar.gz: a4d04ff25ce45b4392e5ad5c5153530446f83256e2b00452999da0c920751416
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 222ebe8277d96856c05c9d712ad0d0e33cea995e7195dada790cf6423e3ad9f16b970c555c9889a1d7eb9082ad9045ca73a00bc95116fc93912f429fc1ded50f
|
|
7
|
+
data.tar.gz: f859bfb3d498ae8bc2c146e5bd8d9be8cadb65a6f3a51135c89bd1f3e86c83007f2602b9e6b115179e7f294dc663e3c96ce9073890511b478689ddf99156e1b9
|
data/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,22 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
5
5
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
6
6
|
|
|
7
|
+
## [3.12.0] - 2025-11-08
|
|
8
|
+
|
|
9
|
+
* Docs updates (@leenyburger, @skryukov, @bn-l)
|
|
10
|
+
* Reimplement devcontainers (@kieraneglin)
|
|
11
|
+
* Support for Inertia.js infinite scroll components (@skyrukov)
|
|
12
|
+
* New merge options (@skryukov)
|
|
13
|
+
|
|
14
|
+
## [3.11.0] - 2025-08-29
|
|
15
|
+
|
|
16
|
+
* Fix Svelte generator (@skryukov)
|
|
17
|
+
* Docs updates for SSR and 2.1.2 (@skryukov)
|
|
18
|
+
* Devcontainers for local dev (@kieraneglin)
|
|
19
|
+
* Add configurable prop transformation (@kieraneglin)
|
|
20
|
+
* Gradual deprecation of null errors because Inertis.js expects an empty object (@skryukov)
|
|
21
|
+
* Allow the more helpful UnknownFormat exception to raise when a static intertia route is requested with a non-HTML format (@skryukov)
|
|
22
|
+
|
|
7
23
|
## [3.10.0] - 2025-07-30
|
|
8
24
|
|
|
9
25
|
* llms.txt in docs (@brandonshar and @skryukov)
|
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module InertiaRails
|
|
2
4
|
class StaticController < InertiaRails.configuration.parent_controller.constantize
|
|
3
5
|
def static
|
|
4
|
-
|
|
6
|
+
respond_to do |format|
|
|
7
|
+
format.html { render inertia: params[:component] }
|
|
8
|
+
end
|
|
5
9
|
end
|
|
6
10
|
end
|
|
7
11
|
end
|
|
@@ -4,6 +4,7 @@ react:
|
|
|
4
4
|
- "@vitejs/plugin-react"
|
|
5
5
|
- "react"
|
|
6
6
|
- "react-dom"
|
|
7
|
+
- "vite@latest"
|
|
7
8
|
packages_ts:
|
|
8
9
|
- "@types/react"
|
|
9
10
|
- "@types/react-dom"
|
|
@@ -29,6 +30,7 @@ vue:
|
|
|
29
30
|
packages:
|
|
30
31
|
- "vue"
|
|
31
32
|
- "@vitejs/plugin-vue"
|
|
33
|
+
- "vite@latest"
|
|
32
34
|
packages_ts:
|
|
33
35
|
- "typescript@~5.6.2"
|
|
34
36
|
- "vue-tsc"
|
|
@@ -52,6 +54,7 @@ svelte4:
|
|
|
52
54
|
packages:
|
|
53
55
|
- "svelte@4"
|
|
54
56
|
- "@sveltejs/vite-plugin-svelte@3"
|
|
57
|
+
- "vite@5"
|
|
55
58
|
packages_ts:
|
|
56
59
|
- "@tsconfig/svelte@4"
|
|
57
60
|
- "svelte-check"
|
|
@@ -76,7 +79,8 @@ svelte:
|
|
|
76
79
|
inertia_package: "@inertiajs/svelte"
|
|
77
80
|
packages:
|
|
78
81
|
- "svelte@5"
|
|
79
|
-
- "@sveltejs/vite-plugin-svelte
|
|
82
|
+
- "@sveltejs/vite-plugin-svelte"
|
|
83
|
+
- "vite@latest"
|
|
80
84
|
packages_ts:
|
|
81
85
|
- "@tsconfig/svelte@5"
|
|
82
86
|
- "svelte-check"
|
|
@@ -128,8 +128,12 @@ module Inertia
|
|
|
128
128
|
add_dependencies(*FRAMEWORKS[framework]['packages_ts'])
|
|
129
129
|
|
|
130
130
|
say 'Copying adding scripts to package.json'
|
|
131
|
-
|
|
132
|
-
|
|
131
|
+
if svelte?
|
|
132
|
+
run 'npm pkg set scripts.check="svelte-check --tsconfig ./tsconfig.json && tsc -p tsconfig.node.json"'
|
|
133
|
+
end
|
|
134
|
+
if framework == 'vue'
|
|
135
|
+
run 'npm pkg set scripts.check="vue-tsc -p tsconfig.app.json && tsc -p tsconfig.node.json"'
|
|
136
|
+
end
|
|
133
137
|
run 'npm pkg set scripts.check="tsc -p tsconfig.app.json && tsc -p tsconfig.node.json"' if framework == 'react'
|
|
134
138
|
end
|
|
135
139
|
|
|
@@ -262,8 +266,9 @@ module Inertia
|
|
|
262
266
|
end
|
|
263
267
|
|
|
264
268
|
def inertia_resolved_version
|
|
269
|
+
package = "@inertiajs/core@#{options[:inertia_version]}"
|
|
265
270
|
@inertia_resolved_version ||= Gem::Version.new(
|
|
266
|
-
`npm show
|
|
271
|
+
`npm show #{package} version --json | tail -n2 | head -n1 | tr -d '", '`.strip
|
|
267
272
|
)
|
|
268
273
|
end
|
|
269
274
|
|
|
@@ -2,11 +2,6 @@ import { createInertiaApp } from '@inertiajs/svelte'
|
|
|
2
2
|
import { mount } from 'svelte';
|
|
3
3
|
|
|
4
4
|
createInertiaApp({
|
|
5
|
-
// Set default page title
|
|
6
|
-
// see https://inertia-rails.dev/guide/title-and-meta
|
|
7
|
-
//
|
|
8
|
-
// title: title => title ? `${title} - App` : 'App',
|
|
9
|
-
|
|
10
5
|
// Disable progress bar
|
|
11
6
|
//
|
|
12
7
|
// see https://inertia-rails.dev/guide/progress-indicators
|
|
@@ -2,11 +2,6 @@ import { createInertiaApp, type ResolvedComponent } from '@inertiajs/svelte'
|
|
|
2
2
|
import { mount } from 'svelte'
|
|
3
3
|
|
|
4
4
|
createInertiaApp({
|
|
5
|
-
// Set default page title
|
|
6
|
-
// see https://inertia-rails.dev/guide/title-and-meta
|
|
7
|
-
//
|
|
8
|
-
// title: title => title ? `${title} - App` : 'App',
|
|
9
|
-
|
|
10
5
|
// Disable progress bar
|
|
11
6
|
//
|
|
12
7
|
// see https://inertia-rails.dev/guide/progress-indicators
|
|
@@ -25,7 +20,7 @@ createInertiaApp({
|
|
|
25
20
|
// and use the following line.
|
|
26
21
|
// see https://inertia-rails.dev/guide/pages#default-layouts
|
|
27
22
|
//
|
|
28
|
-
// return { default: page.default, layout: page.layout || Layout }
|
|
23
|
+
// return { default: page.default, layout: page.layout || Layout } as ResolvedComponent
|
|
29
24
|
|
|
30
25
|
return page
|
|
31
26
|
},
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
|
+
|
|
2
3
|
#
|
|
3
4
|
# Based on AbstractController::Callbacks::ActionFilter
|
|
4
5
|
# https://github.com/rails/rails/blob/v7.2.0/actionpack/lib/abstract_controller/callbacks.rb#L39
|
|
@@ -6,7 +7,7 @@ module InertiaRails
|
|
|
6
7
|
class ActionFilter
|
|
7
8
|
def initialize(conditional_key, actions)
|
|
8
9
|
@conditional_key = conditional_key
|
|
9
|
-
@actions = Array(actions).
|
|
10
|
+
@actions = Array(actions).to_set(&:to_s)
|
|
10
11
|
end
|
|
11
12
|
|
|
12
13
|
def match?(controller)
|
|
@@ -12,6 +12,9 @@ module InertiaRails
|
|
|
12
12
|
# Allows the user to hook into the default rendering behavior and change it to fit their needs
|
|
13
13
|
component_path_resolver: ->(path:, action:) { "#{path}/#{action}" },
|
|
14
14
|
|
|
15
|
+
# A function that transforms the props before they are sent to the client.
|
|
16
|
+
prop_transformer: ->(props:) { props },
|
|
17
|
+
|
|
15
18
|
# DEPRECATED: Let Rails decide which layout should be used based on the
|
|
16
19
|
# controller configuration.
|
|
17
20
|
layout: true,
|
|
@@ -26,8 +29,11 @@ module InertiaRails
|
|
|
26
29
|
# Used to detect version drift between server and client.
|
|
27
30
|
version: nil,
|
|
28
31
|
|
|
29
|
-
# Allows configuring the base controller for StaticController
|
|
32
|
+
# Allows configuring the base controller for StaticController.
|
|
30
33
|
parent_controller: '::ApplicationController',
|
|
34
|
+
|
|
35
|
+
# Whether to include empty `errors` hash to the props when no errors are present.
|
|
36
|
+
always_include_errors_hash: nil,
|
|
31
37
|
}.freeze
|
|
32
38
|
|
|
33
39
|
OPTION_NAMES = DEFAULTS.keys.freeze
|
|
@@ -89,6 +95,10 @@ module InertiaRails
|
|
|
89
95
|
@options[:component_path_resolver].call(path: path, action: action)
|
|
90
96
|
end
|
|
91
97
|
|
|
98
|
+
def prop_transformer(props:)
|
|
99
|
+
@options[:prop_transformer].call(props: props)
|
|
100
|
+
end
|
|
101
|
+
|
|
92
102
|
OPTION_NAMES.each do |option|
|
|
93
103
|
unless method_defined?(option)
|
|
94
104
|
define_method(option) do
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
require_relative
|
|
4
|
-
require_relative
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'inertia_rails'
|
|
4
|
+
require_relative 'helper'
|
|
5
|
+
require_relative 'action_filter'
|
|
6
|
+
require_relative 'meta_tag_builder'
|
|
5
7
|
|
|
6
8
|
module InertiaRails
|
|
7
9
|
module Controller
|
|
@@ -21,8 +23,8 @@ module InertiaRails
|
|
|
21
23
|
return push_to_inertia_share(**(hash || props), &block) if options.empty?
|
|
22
24
|
|
|
23
25
|
push_to_inertia_share do
|
|
24
|
-
next
|
|
25
|
-
next
|
|
26
|
+
next if options[:if] && !options[:if].all? { |filter| instance_exec(&filter) }
|
|
27
|
+
next if options[:unless]&.any? { |filter| instance_exec(&filter) }
|
|
26
28
|
|
|
27
29
|
next hash unless block
|
|
28
30
|
|
|
@@ -81,7 +83,9 @@ module InertiaRails
|
|
|
81
83
|
return options if options.empty?
|
|
82
84
|
|
|
83
85
|
if props.except(:if, :unless, :only, :except).any?
|
|
84
|
-
raise ArgumentError,
|
|
86
|
+
raise ArgumentError,
|
|
87
|
+
'You must not mix shared data and [:if, :unless, :only, :except] options, ' \
|
|
88
|
+
'pass data as a hash or a block.'
|
|
85
89
|
end
|
|
86
90
|
|
|
87
91
|
transform_inertia_share_option(options, :only, :if)
|
|
@@ -110,7 +114,7 @@ module InertiaRails
|
|
|
110
114
|
when InertiaRails::ActionFilter
|
|
111
115
|
-> { filter.match?(self) }
|
|
112
116
|
else
|
|
113
|
-
raise ArgumentError,
|
|
117
|
+
raise ArgumentError, 'You must pass a symbol or a proc as a filter.'
|
|
114
118
|
end
|
|
115
119
|
end
|
|
116
120
|
end
|
|
@@ -136,6 +140,7 @@ module InertiaRails
|
|
|
136
140
|
|
|
137
141
|
def inertia_view_assigns
|
|
138
142
|
return {} unless @_inertia_instance_props
|
|
143
|
+
|
|
139
144
|
view_assigns.except(*@_inertia_skip_props)
|
|
140
145
|
end
|
|
141
146
|
|
|
@@ -144,15 +149,30 @@ module InertiaRails
|
|
|
144
149
|
end
|
|
145
150
|
|
|
146
151
|
def inertia_shared_data
|
|
147
|
-
initial_data =
|
|
152
|
+
initial_data =
|
|
153
|
+
if session[:inertia_errors].present?
|
|
154
|
+
{ errors: session[:inertia_errors] }
|
|
155
|
+
elsif inertia_configuration.always_include_errors_hash
|
|
156
|
+
{ errors: {} }
|
|
157
|
+
else
|
|
158
|
+
if inertia_configuration.always_include_errors_hash.nil?
|
|
159
|
+
InertiaRails.deprecator.warn(
|
|
160
|
+
'To comply with the Inertia protocol, an empty errors hash `{errors: {}}` ' \
|
|
161
|
+
'will be included to all responses by default starting with InertiaRails 4.0. ' \
|
|
162
|
+
'To opt-in now, set `config.always_include_errors_hash = true`. ' \
|
|
163
|
+
'To disable this warning, set it to `false`.'
|
|
164
|
+
)
|
|
165
|
+
end
|
|
166
|
+
{}
|
|
167
|
+
end
|
|
148
168
|
|
|
149
|
-
self.class._inertia_shared_data.filter_map
|
|
169
|
+
self.class._inertia_shared_data.filter_map do |shared_data|
|
|
150
170
|
if shared_data.respond_to?(:call)
|
|
151
171
|
instance_exec(&shared_data)
|
|
152
172
|
else
|
|
153
173
|
shared_data
|
|
154
174
|
end
|
|
155
|
-
|
|
175
|
+
end.reduce(initial_data, &:merge)
|
|
156
176
|
end
|
|
157
177
|
|
|
158
178
|
def inertia_location(url)
|
|
@@ -168,7 +188,7 @@ module InertiaRails
|
|
|
168
188
|
session[:inertia_errors] = inertia_errors.to_hash
|
|
169
189
|
else
|
|
170
190
|
InertiaRails.deprecator.warn(
|
|
171
|
-
|
|
191
|
+
'Object passed to `inertia: { errors: ... }` must respond to `to_hash`. Pass a hash-like object instead.'
|
|
172
192
|
)
|
|
173
193
|
session[:inertia_errors] = inertia_errors
|
|
174
194
|
end
|
|
@@ -2,27 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
module InertiaRails
|
|
4
4
|
class DeferProp < IgnoreOnFirstLoadProp
|
|
5
|
-
|
|
5
|
+
prepend PropMergeable
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
DEFAULT_GROUP = 'default'
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
raise ArgumentError, 'Cannot set both `deep_merge` and `merge` to true' if deep_merge && merge
|
|
9
|
+
attr_reader :group
|
|
11
10
|
|
|
11
|
+
def initialize(**props, &block)
|
|
12
12
|
super(&block)
|
|
13
13
|
|
|
14
|
-
@group = group || DEFAULT_GROUP
|
|
15
|
-
@merge = merge || deep_merge
|
|
16
|
-
@deep_merge = deep_merge
|
|
17
|
-
@match_on = match_on.nil? ? nil : Array(match_on)
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
def merge?
|
|
21
|
-
@merge
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
def deep_merge?
|
|
25
|
-
@deep_merge
|
|
14
|
+
@group = props[:group] || DEFAULT_GROUP
|
|
26
15
|
end
|
|
27
16
|
end
|
|
28
17
|
end
|
data/lib/inertia_rails/engine.rb
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'middleware'
|
|
4
|
+
require_relative 'controller'
|
|
3
5
|
|
|
4
6
|
module InertiaRails
|
|
5
7
|
class Engine < ::Rails::Engine
|
|
6
|
-
initializer
|
|
8
|
+
initializer 'inertia_rails.configure_rails_initialization' do |app|
|
|
7
9
|
app.middleware.use ::InertiaRails::Middleware
|
|
8
10
|
end
|
|
9
11
|
|
|
10
|
-
initializer
|
|
12
|
+
initializer 'inertia_rails.action_controller' do
|
|
11
13
|
ActiveSupport.on_load(:action_controller_base) do
|
|
12
14
|
include ::InertiaRails::Controller
|
|
13
15
|
end
|
data/lib/inertia_rails/helper.rb
CHANGED
|
@@ -1,32 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
require_relative 'inertia_rails'
|
|
2
4
|
|
|
3
|
-
module InertiaRails
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
module InertiaRails
|
|
6
|
+
module Helper
|
|
7
|
+
def inertia_ssr_head
|
|
8
|
+
controller.instance_variable_get('@_inertia_ssr_head')
|
|
9
|
+
end
|
|
7
10
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
def inertia_headers
|
|
12
|
+
InertiaRails.deprecator.warn(
|
|
13
|
+
'`inertia_headers` is deprecated and will be removed in InertiaRails 4.0, use `inertia_ssr_head` instead.'
|
|
14
|
+
)
|
|
15
|
+
inertia_ssr_head
|
|
16
|
+
end
|
|
14
17
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
+
def inertia_rendering?
|
|
19
|
+
controller.instance_variable_get('@_inertia_rendering')
|
|
20
|
+
end
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
def inertia_page
|
|
23
|
+
controller.instance_variable_get('@_inertia_page')
|
|
24
|
+
end
|
|
22
25
|
|
|
23
|
-
|
|
24
|
-
|
|
26
|
+
def inertia_meta_tags
|
|
27
|
+
meta_tag_data = (inertia_page || {}).dig(:props, :_inertia_meta) || []
|
|
25
28
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
+
meta_tags = meta_tag_data.map do |inertia_meta_tag|
|
|
30
|
+
inertia_meta_tag.to_tag(tag)
|
|
31
|
+
end
|
|
29
32
|
|
|
30
|
-
|
|
33
|
+
safe_join(meta_tags, "\n")
|
|
34
|
+
end
|
|
31
35
|
end
|
|
32
36
|
end
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'inertia_rails/prop_mergeable'
|
|
3
4
|
require 'inertia_rails/base_prop'
|
|
4
5
|
require 'inertia_rails/ignore_on_first_load_prop'
|
|
5
6
|
require 'inertia_rails/always_prop'
|
|
@@ -7,6 +8,7 @@ require 'inertia_rails/lazy_prop'
|
|
|
7
8
|
require 'inertia_rails/optional_prop'
|
|
8
9
|
require 'inertia_rails/defer_prop'
|
|
9
10
|
require 'inertia_rails/merge_prop'
|
|
11
|
+
require 'inertia_rails/scroll_prop'
|
|
10
12
|
require 'inertia_rails/configuration'
|
|
11
13
|
require 'inertia_rails/meta_tag'
|
|
12
14
|
|
|
@@ -34,8 +36,8 @@ module InertiaRails
|
|
|
34
36
|
AlwaysProp.new(&block)
|
|
35
37
|
end
|
|
36
38
|
|
|
37
|
-
def merge(
|
|
38
|
-
MergeProp.new(
|
|
39
|
+
def merge(...)
|
|
40
|
+
MergeProp.new(...)
|
|
39
41
|
end
|
|
40
42
|
|
|
41
43
|
def deep_merge(match_on: nil, &block)
|
|
@@ -45,5 +47,9 @@ module InertiaRails
|
|
|
45
47
|
def defer(group: nil, merge: nil, deep_merge: nil, match_on: nil, &block)
|
|
46
48
|
DeferProp.new(group: group, merge: merge, deep_merge: deep_merge, match_on: match_on, &block)
|
|
47
49
|
end
|
|
50
|
+
|
|
51
|
+
def scroll(metadata = nil, **options, &block)
|
|
52
|
+
ScrollProp.new(metadata: metadata, **options, &block)
|
|
53
|
+
end
|
|
48
54
|
end
|
|
49
55
|
end
|
|
@@ -2,20 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
module InertiaRails
|
|
4
4
|
class MergeProp < BaseProp
|
|
5
|
-
|
|
5
|
+
prepend PropMergeable
|
|
6
6
|
|
|
7
|
-
def initialize(
|
|
7
|
+
def initialize(**_props, &block)
|
|
8
8
|
super(&block)
|
|
9
|
-
@
|
|
10
|
-
@match_on = match_on.nil? ? nil : Array(match_on)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def merge?
|
|
14
|
-
true
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def deep_merge?
|
|
18
|
-
@deep_merge
|
|
9
|
+
@merge = true
|
|
19
10
|
end
|
|
20
11
|
end
|
|
21
12
|
end
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module InertiaRails
|
|
4
|
+
module PropMergeable
|
|
5
|
+
attr_reader :match_on, :appends_at_paths, :prepends_at_paths
|
|
6
|
+
|
|
7
|
+
def initialize(**props, &block)
|
|
8
|
+
raise ArgumentError, 'Cannot set both `deep_merge` and `merge` to true' if props[:deep_merge] && props[:merge]
|
|
9
|
+
|
|
10
|
+
@deep_merge = props.fetch(:deep_merge, false)
|
|
11
|
+
@merge = props[:merge] || @deep_merge
|
|
12
|
+
@match_on = props[:match_on].nil? ? nil : Array(props[:match_on])
|
|
13
|
+
@appends_at_paths = []
|
|
14
|
+
@prepends_at_paths = []
|
|
15
|
+
@append = true
|
|
16
|
+
|
|
17
|
+
append(props[:append]) if props.key?(:append)
|
|
18
|
+
prepend(props[:prepend]) if props.key?(:prepend)
|
|
19
|
+
|
|
20
|
+
super
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def appends_at_root?
|
|
24
|
+
@append && merges_at_root?
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def prepends_at_root?
|
|
28
|
+
!@append && merges_at_root?
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def merges_at_root?
|
|
32
|
+
merge? && appends_at_paths.none? && prepends_at_paths.none?
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def merge?
|
|
36
|
+
@merge
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def deep_merge?
|
|
40
|
+
@deep_merge
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def append(path, match_on: nil)
|
|
46
|
+
case path
|
|
47
|
+
when TrueClass, FalseClass
|
|
48
|
+
@append = path
|
|
49
|
+
when String
|
|
50
|
+
@appends_at_paths << path
|
|
51
|
+
when Array
|
|
52
|
+
@appends_at_paths += path
|
|
53
|
+
when Hash
|
|
54
|
+
@match_on ||= []
|
|
55
|
+
path.each do |key, value|
|
|
56
|
+
@appends_at_paths << key.to_s
|
|
57
|
+
@match_on << "#{key}.#{value}" if value
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
(@match_on ||= []) << "#{path}.#{match_on}" if match_on && path.is_a?(String)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def prepend(path, match_on: nil)
|
|
65
|
+
case path
|
|
66
|
+
when TrueClass, FalseClass
|
|
67
|
+
@append = !path
|
|
68
|
+
when String
|
|
69
|
+
@prepends_at_paths << path
|
|
70
|
+
when Array
|
|
71
|
+
@prepends_at_paths += path
|
|
72
|
+
when Hash
|
|
73
|
+
@match_on ||= []
|
|
74
|
+
path.each do |key, value|
|
|
75
|
+
@prepends_at_paths << key.to_s
|
|
76
|
+
@match_on << "#{key}.#{value}" if value
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
(@match_on ||= []) << "#{path}.#{match_on}" if match_on && path.is_a?(String)
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
@@ -90,14 +90,27 @@ module InertiaRails
|
|
|
90
90
|
end
|
|
91
91
|
|
|
92
92
|
def computed_props
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
93
|
+
# rubocop:disable Style/MultilineBlockChain
|
|
94
|
+
merge_props(shared_data, props)
|
|
95
|
+
.then do |merged_props| # Always keep errors in the props
|
|
96
|
+
if merged_props.key?(:errors) && !merged_props[:errors].is_a?(BaseProp)
|
|
97
|
+
errors = merged_props[:errors]
|
|
98
|
+
merged_props[:errors] = InertiaRails.always { errors }
|
|
99
|
+
end
|
|
100
|
+
merged_props
|
|
101
|
+
end
|
|
102
|
+
.then { |props| deep_transform_props(props) } # Internal hydration/filtering
|
|
103
|
+
.then { |props| configuration.prop_transformer(props: props) } # Apply user-defined prop transformer
|
|
104
|
+
.tap do |props| # Add meta tags last (never transformed)
|
|
105
|
+
props[:_inertia_meta] = meta_tags if meta_tags.present?
|
|
96
106
|
end
|
|
107
|
+
# rubocop:enable Style/MultilineBlockChain
|
|
97
108
|
end
|
|
98
109
|
|
|
99
110
|
def page
|
|
100
|
-
|
|
111
|
+
return @page if defined?(@page)
|
|
112
|
+
|
|
113
|
+
@page = {
|
|
101
114
|
component: component,
|
|
102
115
|
props: computed_props,
|
|
103
116
|
url: @request.original_fullpath,
|
|
@@ -107,21 +120,11 @@ module InertiaRails
|
|
|
107
120
|
}
|
|
108
121
|
|
|
109
122
|
deferred_props = deferred_props_keys
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
prop.deep_merge?
|
|
114
|
-
end
|
|
123
|
+
@page[:deferredProps] = deferred_props if deferred_props.present?
|
|
124
|
+
@page[:scrollProps] = scroll_props if scroll_props.present?
|
|
125
|
+
@page.merge!(resolve_merge_props)
|
|
115
126
|
|
|
116
|
-
|
|
117
|
-
prop.match_on.map { |ms| "#{key}.#{ms}" } if prop.match_on.present?
|
|
118
|
-
end.flatten
|
|
119
|
-
|
|
120
|
-
default_page[:mergeProps] = merge_props.map(&:first) if merge_props.present?
|
|
121
|
-
default_page[:deepMergeProps] = deep_merge_props.map(&:first) if deep_merge_props.present?
|
|
122
|
-
default_page[:matchPropsOn] = match_props_on if match_props_on.present?
|
|
123
|
-
|
|
124
|
-
default_page
|
|
127
|
+
@page
|
|
125
128
|
end
|
|
126
129
|
|
|
127
130
|
def deep_transform_props(props, parent_path = [])
|
|
@@ -153,10 +156,28 @@ module InertiaRails
|
|
|
153
156
|
end
|
|
154
157
|
end
|
|
155
158
|
|
|
156
|
-
def
|
|
157
|
-
|
|
159
|
+
def resolve_merge_props
|
|
160
|
+
deep_merge_props, merge_props = all_merge_props.partition do |_key, prop|
|
|
161
|
+
prop.deep_merge?
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
{
|
|
165
|
+
mergeProps: append_merge_props(merge_props),
|
|
166
|
+
prependProps: prepend_merge_props(merge_props),
|
|
167
|
+
deepMergeProps: deep_merge_props.map!(&:first),
|
|
168
|
+
matchPropsOn: resolve_match_on_props,
|
|
169
|
+
}.delete_if { |_, v| v.blank? }
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def resolve_match_on_props
|
|
173
|
+
all_merge_props.filter_map do |key, prop|
|
|
174
|
+
prop.match_on.map! { |ms| "#{key}.#{ms}" } if prop.match_on.present?
|
|
175
|
+
end.flatten
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def requested_merge_props
|
|
179
|
+
@requested_merge_props ||= @props.select do |key, prop|
|
|
158
180
|
next unless prop.try(:merge?)
|
|
159
|
-
next if reset_keys.include?(key)
|
|
160
181
|
next if rendering_partial_component? && (
|
|
161
182
|
(partial_keys.present? && partial_keys.exclude?(key.name)) ||
|
|
162
183
|
(partial_except_keys.present? && partial_except_keys.include?(key.name))
|
|
@@ -166,16 +187,64 @@ module InertiaRails
|
|
|
166
187
|
end
|
|
167
188
|
end
|
|
168
189
|
|
|
190
|
+
def append_merge_props(props)
|
|
191
|
+
return props if props.empty?
|
|
192
|
+
|
|
193
|
+
root_append_props, nested_append_props = props.partition { |_key, prop| prop.appends_at_root? }
|
|
194
|
+
|
|
195
|
+
result = Set.new(root_append_props.map!(&:first))
|
|
196
|
+
|
|
197
|
+
nested_append_props.each do |key, prop|
|
|
198
|
+
prop.appends_at_paths.each do |path|
|
|
199
|
+
result.add("#{key}.#{path}")
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
result.to_a
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def prepend_merge_props(props)
|
|
207
|
+
return props if props.empty?
|
|
208
|
+
|
|
209
|
+
root_prepend_props, nested_prepend_props = props.partition { |_key, prop| prop.prepends_at_root? }
|
|
210
|
+
|
|
211
|
+
result = Set.new(root_prepend_props.map!(&:first))
|
|
212
|
+
|
|
213
|
+
nested_prepend_props.each do |key, prop|
|
|
214
|
+
prop.prepends_at_paths.each do |path|
|
|
215
|
+
result.add("#{key}.#{path}")
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
|
|
219
|
+
result.to_a
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
def scroll_props
|
|
223
|
+
return @scroll_props if defined?(@scroll_props)
|
|
224
|
+
|
|
225
|
+
@scroll_props = {}
|
|
226
|
+
requested_merge_props.each do |key, prop|
|
|
227
|
+
next unless prop.is_a?(ScrollProp)
|
|
228
|
+
|
|
229
|
+
@scroll_props[key] = prop.metadata.merge!(reset: reset_keys.include?(key))
|
|
230
|
+
end
|
|
231
|
+
@scroll_props
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def all_merge_props
|
|
235
|
+
@all_merge_props ||= requested_merge_props.reject { |key,| reset_keys.include?(key) }
|
|
236
|
+
end
|
|
237
|
+
|
|
169
238
|
def partial_keys
|
|
170
|
-
@partial_keys ||= (@request.headers['X-Inertia-Partial-Data'] || '').split(',').
|
|
239
|
+
@partial_keys ||= (@request.headers['X-Inertia-Partial-Data'] || '').split(',').compact_blank!
|
|
171
240
|
end
|
|
172
241
|
|
|
173
242
|
def reset_keys
|
|
174
|
-
(@request.headers['X-Inertia-Reset'] || '').split(',').
|
|
243
|
+
@reset_keys ||= (@request.headers['X-Inertia-Reset'] || '').split(',').compact_blank!.map!(&:to_sym)
|
|
175
244
|
end
|
|
176
245
|
|
|
177
246
|
def partial_except_keys
|
|
178
|
-
(@request.headers['X-Inertia-Partial-Except'] || '').split(',').
|
|
247
|
+
@partial_except_keys ||= (@request.headers['X-Inertia-Partial-Except'] || '').split(',').compact_blank!
|
|
179
248
|
end
|
|
180
249
|
|
|
181
250
|
def rendering_partial_component?
|
data/lib/inertia_rails/rspec.rb
CHANGED
|
@@ -1,30 +1,32 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'rspec/core'
|
|
4
|
+
require 'rspec/matchers'
|
|
3
5
|
|
|
4
6
|
module InertiaRails
|
|
5
7
|
module RSpec
|
|
6
8
|
class InertiaRenderWrapper
|
|
7
9
|
attr_reader :view_data, :props, :component
|
|
8
|
-
|
|
10
|
+
|
|
9
11
|
def initialize
|
|
10
12
|
@view_data = nil
|
|
11
13
|
@props = nil
|
|
12
14
|
@component = nil
|
|
13
15
|
end
|
|
14
|
-
|
|
16
|
+
|
|
15
17
|
def call(params)
|
|
16
|
-
|
|
18
|
+
assign_locals(params)
|
|
17
19
|
@render_method&.call(params)
|
|
18
20
|
end
|
|
19
|
-
|
|
21
|
+
|
|
20
22
|
def wrap_render(render_method)
|
|
21
23
|
@render_method = render_method
|
|
22
24
|
self
|
|
23
25
|
end
|
|
24
|
-
|
|
26
|
+
|
|
25
27
|
protected
|
|
26
|
-
|
|
27
|
-
def
|
|
28
|
+
|
|
29
|
+
def assign_locals(params)
|
|
28
30
|
if params[:locals].present?
|
|
29
31
|
@view_data = params[:locals].except(:page)
|
|
30
32
|
@props = params[:locals][:page][:props]
|
|
@@ -33,18 +35,24 @@ module InertiaRails
|
|
|
33
35
|
# Sequential Inertia request
|
|
34
36
|
@view_data = {}
|
|
35
37
|
json = JSON.parse(params[:json])
|
|
36
|
-
@props = json[
|
|
37
|
-
@component = json[
|
|
38
|
+
@props = json['props']
|
|
39
|
+
@component = json['component']
|
|
38
40
|
end
|
|
39
41
|
end
|
|
40
42
|
end
|
|
41
43
|
|
|
42
44
|
module Helpers
|
|
43
45
|
def inertia
|
|
44
|
-
|
|
46
|
+
unless inertia_tests_setup?
|
|
47
|
+
raise "Inertia test helpers aren't set up! " \
|
|
48
|
+
'Make sure you add `inertia: true` to describe blocks using inertia tests.'
|
|
49
|
+
end
|
|
45
50
|
|
|
46
51
|
if @_inertia_render_wrapper.nil? && !::RSpec.configuration.inertia[:skip_missing_renderer_warnings]
|
|
47
|
-
warn 'WARNING: the test never created an Inertia renderer.
|
|
52
|
+
warn 'WARNING: the test never created an Inertia renderer. ' \
|
|
53
|
+
"Maybe the code wasn't able to reach a `render inertia:` call? If this was intended, " \
|
|
54
|
+
"or you don't want to see this message, " \
|
|
55
|
+
'set ::RSpec.configuration.inertia[:skip_missing_renderer_warnings] = true'
|
|
48
56
|
end
|
|
49
57
|
@_inertia_render_wrapper
|
|
50
58
|
end
|
|
@@ -57,8 +65,8 @@ module InertiaRails
|
|
|
57
65
|
@_inertia_render_wrapper = InertiaRenderWrapper.new.wrap_render(render)
|
|
58
66
|
end
|
|
59
67
|
|
|
60
|
-
protected
|
|
61
|
-
|
|
68
|
+
protected
|
|
69
|
+
|
|
62
70
|
def inertia_tests_setup?
|
|
63
71
|
::RSpec.current_example.metadata.fetch(:inertia, false)
|
|
64
72
|
end
|
|
@@ -67,9 +75,9 @@ module InertiaRails
|
|
|
67
75
|
end
|
|
68
76
|
|
|
69
77
|
RSpec.configure do |config|
|
|
70
|
-
config.include
|
|
78
|
+
config.include InertiaRails::RSpec::Helpers
|
|
71
79
|
config.add_setting :inertia, default: {
|
|
72
|
-
skip_missing_renderer_warnings: false
|
|
80
|
+
skip_missing_renderer_warnings: false,
|
|
73
81
|
}
|
|
74
82
|
|
|
75
83
|
config.before(:each, inertia: true) do
|
|
@@ -106,13 +114,14 @@ RSpec::Matchers.define :render_component do |expected_component|
|
|
|
106
114
|
end
|
|
107
115
|
|
|
108
116
|
failure_message do |inertia|
|
|
109
|
-
"expected rendered inertia component to be #{expected_component},
|
|
117
|
+
"expected rendered inertia component to be #{expected_component}, " \
|
|
118
|
+
"instead received #{inertia.component || 'nothing'}"
|
|
110
119
|
end
|
|
111
120
|
end
|
|
112
121
|
|
|
113
122
|
RSpec::Matchers.define :have_exact_view_data do |expected_view_data|
|
|
114
123
|
match do |inertia|
|
|
115
|
-
expect(inertia.view_data).to eq expected_view_data
|
|
124
|
+
expect(inertia.view_data).to eq expected_view_data
|
|
116
125
|
end
|
|
117
126
|
|
|
118
127
|
failure_message do |inertia|
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module InertiaRails
|
|
4
|
+
module ScrollMetadata
|
|
5
|
+
class MissingMetadataAdapterError < StandardError; end
|
|
6
|
+
|
|
7
|
+
class Props
|
|
8
|
+
def initialize(page_name:, previous_page:, next_page:, current_page:)
|
|
9
|
+
@page_name = page_name
|
|
10
|
+
@previous_page = previous_page
|
|
11
|
+
@next_page = next_page
|
|
12
|
+
@current_page = current_page
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def as_json(_options = nil)
|
|
16
|
+
{
|
|
17
|
+
pageName: @page_name,
|
|
18
|
+
previousPage: @previous_page,
|
|
19
|
+
nextPage: @next_page,
|
|
20
|
+
currentPage: @current_page,
|
|
21
|
+
}
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
class KaminariAdapter
|
|
26
|
+
def match?(metadata)
|
|
27
|
+
defined?(Kaminari) && metadata.is_a?(Kaminari::PageScopeMethods)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def call(metadata, **_options)
|
|
31
|
+
{
|
|
32
|
+
page_name: (Kaminari.config.param_name || 'page').to_s,
|
|
33
|
+
previous_page: metadata.prev_page,
|
|
34
|
+
next_page: metadata.next_page,
|
|
35
|
+
current_page: metadata.current_page,
|
|
36
|
+
}
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class PagyAdapter
|
|
41
|
+
def match?(metadata)
|
|
42
|
+
defined?(Pagy) && metadata.is_a?(Pagy)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def call(metadata, **_options)
|
|
46
|
+
page_name = metadata.respond_to?(:vars) ? metadata.vars.fetch(:page_param) : metadata.options[:page_key]
|
|
47
|
+
{
|
|
48
|
+
page_name: page_name.to_s,
|
|
49
|
+
previous_page: metadata.try(:prev) || metadata.try(:previous),
|
|
50
|
+
next_page: metadata.next,
|
|
51
|
+
current_page: metadata.page,
|
|
52
|
+
}
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
class HashAdapter
|
|
57
|
+
def match?(metadata)
|
|
58
|
+
metadata.is_a?(Hash)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def call(metadata, **_options)
|
|
62
|
+
{
|
|
63
|
+
page_name: metadata.fetch(:page_name),
|
|
64
|
+
previous_page: metadata.fetch(:previous_page),
|
|
65
|
+
next_page: metadata.fetch(:next_page),
|
|
66
|
+
current_page: metadata.fetch(:current_page),
|
|
67
|
+
}
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
class << self
|
|
72
|
+
attr_accessor :adapters
|
|
73
|
+
|
|
74
|
+
def extract(metadata, **options)
|
|
75
|
+
overrides = options.slice(:page_name, :previous_page, :next_page, :current_page)
|
|
76
|
+
|
|
77
|
+
adapters.each do |adapter|
|
|
78
|
+
next unless adapter.match?(metadata)
|
|
79
|
+
|
|
80
|
+
return Props.new(**adapter.call(metadata, **options).merge!(overrides)).as_json
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
begin
|
|
84
|
+
Props.new(**overrides).as_json
|
|
85
|
+
rescue ArgumentError
|
|
86
|
+
raise MissingMetadataAdapterError, "No ScrollMetadata adapter found for #{metadata}"
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def register_adapter(adapter)
|
|
91
|
+
adapters.unshift(adapter.new)
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
self.adapters = [KaminariAdapter, PagyAdapter, HashAdapter].map(&:new)
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'scroll_metadata'
|
|
4
|
+
|
|
5
|
+
module InertiaRails
|
|
6
|
+
class ScrollProp < BaseProp
|
|
7
|
+
prepend PropMergeable
|
|
8
|
+
|
|
9
|
+
def initialize(**options, &block)
|
|
10
|
+
super(&block)
|
|
11
|
+
|
|
12
|
+
@merge = true
|
|
13
|
+
@metadata = options.delete(:metadata)
|
|
14
|
+
@wrapper = options.delete(:wrapper)
|
|
15
|
+
|
|
16
|
+
@options = options
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def call(controller)
|
|
20
|
+
@value = super
|
|
21
|
+
configure_merge_intent(controller.request.headers['X-Inertia-Infinite-Scroll-Merge-Intent'])
|
|
22
|
+
@value
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def metadata
|
|
26
|
+
ScrollMetadata.extract(@metadata, **@options)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def configure_merge_intent(scroll_intent)
|
|
32
|
+
scroll_intent == 'prepend' ? prepend(@wrapper || true) : append(@wrapper || true)
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# Patch BetterErrors::Middleware to render HTML for Inertia requests
|
|
2
4
|
#
|
|
3
5
|
# Original source:
|
|
@@ -7,13 +9,11 @@
|
|
|
7
9
|
module InertiaRails
|
|
8
10
|
module InertiaBetterErrors
|
|
9
11
|
def text?(env)
|
|
10
|
-
return false if env[
|
|
12
|
+
return false if env['HTTP_X_INERTIA']
|
|
11
13
|
|
|
12
14
|
super
|
|
13
15
|
end
|
|
14
16
|
end
|
|
15
17
|
end
|
|
16
18
|
|
|
17
|
-
if defined?(BetterErrors)
|
|
18
|
-
BetterErrors::Middleware.include InertiaRails::InertiaBetterErrors
|
|
19
|
-
end
|
|
19
|
+
BetterErrors::Middleware.include InertiaRails::InertiaBetterErrors if defined?(BetterErrors)
|
|
@@ -1,17 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
# Patch ActionDispatch::DebugExceptions to render HTML for Inertia requests
|
|
2
4
|
#
|
|
3
|
-
# Rails has introduced text rendering for XHR requests with Rails 4.1 and
|
|
4
|
-
# changed the implementation in 4.2, 5.0 and 5.1 (unchanged since then).
|
|
5
|
-
#
|
|
6
5
|
# The original source needs to be patched, so that Inertia requests are
|
|
7
6
|
# NOT responded with plain text, but with HTML.
|
|
7
|
+
#
|
|
8
|
+
# Original source (unchanged since Rails 5.1):
|
|
9
|
+
# https://github.com/rails/rails/blob/5-1-stable/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
|
|
10
|
+
# https://github.com/rails/rails/blob/8-0-stable/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
|
|
11
|
+
#
|
|
8
12
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
module InertiaRails
|
|
14
|
+
module InertiaDebugExceptions
|
|
15
|
+
def render_for_browser_request(request, wrapper)
|
|
16
|
+
template = create_template(request, wrapper)
|
|
17
|
+
file = "rescues/#{wrapper.rescue_template}"
|
|
18
|
+
|
|
19
|
+
if request.xhr? && !request.headers['X-Inertia'] # <<<< this line is changed only
|
|
20
|
+
body = template.render(template: file, layout: false, formats: [:text])
|
|
21
|
+
format = 'text/plain'
|
|
22
|
+
else
|
|
23
|
+
body = template.render(template: file, layout: 'rescues/layout')
|
|
24
|
+
format = 'text/html'
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
render(wrapper.status_code, body, format)
|
|
28
|
+
end
|
|
16
29
|
end
|
|
17
30
|
end
|
|
31
|
+
|
|
32
|
+
if defined?(ActionDispatch::DebugExceptions)
|
|
33
|
+
ActionDispatch::DebugExceptions.prepend InertiaRails::InertiaDebugExceptions
|
|
34
|
+
end
|
data/lib/patches/mapper.rb
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
module InertiaRails
|
|
2
4
|
module InertiaMapper
|
|
3
5
|
def inertia(*args, **options)
|
|
@@ -12,7 +14,10 @@ module InertiaRails
|
|
|
12
14
|
if path.is_a?(Hash)
|
|
13
15
|
path.first
|
|
14
16
|
elsif resource_scope?
|
|
15
|
-
[path,
|
|
17
|
+
[path,
|
|
18
|
+
InertiaRails.configuration.component_path_resolver(
|
|
19
|
+
path: [@scope[:module], @scope[:controller]].compact.join('/'), action: path
|
|
20
|
+
)]
|
|
16
21
|
elsif @scope[:module].blank?
|
|
17
22
|
[path, path]
|
|
18
23
|
else
|
data/lib/patches/request.rb
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
1
3
|
namespace :inertia_rails do
|
|
2
4
|
namespace :install do
|
|
3
|
-
desc
|
|
4
|
-
task :
|
|
5
|
+
desc 'Installs inertia_rails packages and configurations for a React based app'
|
|
6
|
+
task react: :environment do
|
|
5
7
|
system 'rails g inertia_rails:install --front_end react'
|
|
6
8
|
end
|
|
7
|
-
desc
|
|
9
|
+
desc 'Installs inertia_rails packages and configurations for a Vue based app'
|
|
8
10
|
task vue: :environment do
|
|
9
11
|
system 'rails g inertia_rails:install --front_end vue'
|
|
10
12
|
end
|
|
11
|
-
desc
|
|
13
|
+
desc 'Installs inertia_rails packages and configurations for a Svelte based app'
|
|
12
14
|
task svelte: :environment do
|
|
13
15
|
system 'rails g inertia_rails:install --front_end svelte'
|
|
14
16
|
end
|
|
15
17
|
end
|
|
16
|
-
end
|
|
18
|
+
end
|
metadata
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: inertia_rails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.12.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Brian Knoles
|
|
8
8
|
- Brandon Shar
|
|
9
9
|
- Eugene Granovsky
|
|
10
|
-
autorequire:
|
|
11
10
|
bindir: bin
|
|
12
11
|
cert_chain: []
|
|
13
|
-
date: 2025-
|
|
12
|
+
date: 2025-11-08 00:00:00.000000000 Z
|
|
14
13
|
dependencies:
|
|
15
14
|
- !ruby/object:Gem::Dependency
|
|
16
15
|
name: railties
|
|
@@ -230,13 +229,14 @@ files:
|
|
|
230
229
|
- lib/inertia_rails/meta_tag_builder.rb
|
|
231
230
|
- lib/inertia_rails/middleware.rb
|
|
232
231
|
- lib/inertia_rails/optional_prop.rb
|
|
232
|
+
- lib/inertia_rails/prop_mergeable.rb
|
|
233
233
|
- lib/inertia_rails/renderer.rb
|
|
234
234
|
- lib/inertia_rails/rspec.rb
|
|
235
|
+
- lib/inertia_rails/scroll_metadata.rb
|
|
236
|
+
- lib/inertia_rails/scroll_prop.rb
|
|
235
237
|
- lib/inertia_rails/version.rb
|
|
236
238
|
- lib/patches/better_errors.rb
|
|
237
239
|
- lib/patches/debug_exceptions.rb
|
|
238
|
-
- lib/patches/debug_exceptions/patch-5-0.rb
|
|
239
|
-
- lib/patches/debug_exceptions/patch-5-1.rb
|
|
240
240
|
- lib/patches/mapper.rb
|
|
241
241
|
- lib/patches/request.rb
|
|
242
242
|
- lib/tasks/inertia_rails.rake
|
|
@@ -250,7 +250,6 @@ metadata:
|
|
|
250
250
|
homepage_uri: https://github.com/inertiajs/inertia-rails
|
|
251
251
|
source_code_uri: https://github.com/inertiajs/inertia-rails
|
|
252
252
|
rubygems_mfa_required: 'true'
|
|
253
|
-
post_install_message:
|
|
254
253
|
rdoc_options: []
|
|
255
254
|
require_paths:
|
|
256
255
|
- lib
|
|
@@ -265,8 +264,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
265
264
|
- !ruby/object:Gem::Version
|
|
266
265
|
version: '0'
|
|
267
266
|
requirements: []
|
|
268
|
-
rubygems_version: 3.
|
|
269
|
-
signing_key:
|
|
267
|
+
rubygems_version: 3.6.2
|
|
270
268
|
specification_version: 4
|
|
271
269
|
summary: Inertia.js adapter for Rails
|
|
272
270
|
test_files: []
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
# Patch ActionDispatch::DebugExceptions to render HTML for Inertia requests
|
|
2
|
-
#
|
|
3
|
-
# Original source:
|
|
4
|
-
# https://github.com/rails/rails/blob/5-0-stable/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
|
|
5
|
-
#
|
|
6
|
-
|
|
7
|
-
module InertiaRails
|
|
8
|
-
module InertiaDebugExceptions
|
|
9
|
-
def render_for_default_application(request, wrapper)
|
|
10
|
-
template = create_template(request, wrapper)
|
|
11
|
-
file = "rescues/#{wrapper.rescue_template}"
|
|
12
|
-
|
|
13
|
-
if request.xhr? && !request.headers['X-Inertia'] # <<<< this line is changed only
|
|
14
|
-
body = template.render(template: file, layout: false, formats: [:text])
|
|
15
|
-
format = "text/plain"
|
|
16
|
-
else
|
|
17
|
-
body = template.render(template: file, layout: 'rescues/layout')
|
|
18
|
-
format = "text/html"
|
|
19
|
-
end
|
|
20
|
-
render(wrapper.status_code, body, format)
|
|
21
|
-
end
|
|
22
|
-
end
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
if defined?(ActionDispatch::DebugExceptions)
|
|
26
|
-
ActionDispatch::DebugExceptions.prepend InertiaRails::InertiaDebugExceptions
|
|
27
|
-
end
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
# Patch ActionDispatch::DebugExceptions to render HTML for Inertia requests
|
|
2
|
-
#
|
|
3
|
-
# Original source (unchanged since Rails 5.1):
|
|
4
|
-
# https://github.com/rails/rails/blob/5-1-stable/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
|
|
5
|
-
# https://github.com/rails/rails/blob/5-2-stable/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
|
|
6
|
-
# https://github.com/rails/rails/blob/6-0-stable/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
|
|
7
|
-
#
|
|
8
|
-
|
|
9
|
-
module InertiaRails
|
|
10
|
-
module InertiaDebugExceptions
|
|
11
|
-
def render_for_browser_request(request, wrapper)
|
|
12
|
-
template = create_template(request, wrapper)
|
|
13
|
-
file = "rescues/#{wrapper.rescue_template}"
|
|
14
|
-
|
|
15
|
-
if request.xhr? && !request.headers['X-Inertia'] # <<<< this line is changed only
|
|
16
|
-
body = template.render(template: file, layout: false, formats: [:text])
|
|
17
|
-
format = "text/plain"
|
|
18
|
-
else
|
|
19
|
-
body = template.render(template: file, layout: "rescues/layout")
|
|
20
|
-
format = "text/html"
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
render(wrapper.status_code, body, format)
|
|
24
|
-
end
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
if defined?(ActionDispatch::DebugExceptions)
|
|
29
|
-
ActionDispatch::DebugExceptions.prepend InertiaRails::InertiaDebugExceptions
|
|
30
|
-
end
|