inertia_rails 3.21.1 → 3.21.2
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 +7 -0
- data/README.md +117 -309
- data/lib/generators/inertia/install/install_generator.rb +5 -4
- data/lib/generators/inertia/install/js_package_manager.rb +3 -2
- data/lib/inertia_rails/defer_prop.rb +5 -0
- data/lib/inertia_rails/helper.rb +7 -1
- data/lib/inertia_rails/props_resolver.rb +40 -18
- data/lib/inertia_rails/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 190a5d8589ff4eed036766ab20f769f4bb330e09e3097a6682a30c9a8121ceef
|
|
4
|
+
data.tar.gz: 54f4aac04e72db5de364d525851a68de80590aed5ae1220055871d10cbb3ef05
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9c1f35a30b2357eb934fdf33d4f6d51067d0771de5d1081093be4e9858bc9022bde74b799b40d18a3b59e09ca9d8811b4c8fbb91d0062b4a9280b40ab9bca7c5
|
|
7
|
+
data.tar.gz: a47aec16b0e2502305cfa41c48941586036bd322cc74c84f3f6cfb783aeb7b97835bc810f6e35ef1b70c40554a945e05979123cf710819eec50aa6ea2978c8ea
|
data/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [3.21.2] - 2026-06-09
|
|
10
|
+
|
|
11
|
+
* Add `rescue: true` option to `InertiaRails.defer` to rescue and report exceptions raised while resolving a deferred prop (@skryukov)
|
|
12
|
+
* Add CSP nonce to the initial page script when needed (@nicholaspufal)
|
|
13
|
+
* Fix Vite install to use the configured package manager in the generator (@akicho8)
|
|
14
|
+
* Fix TypeScript packages installed as dependencies instead of devDependencies (@alec-c4)
|
|
15
|
+
|
|
9
16
|
## [3.21.1] - 2026-05-19
|
|
10
17
|
|
|
11
18
|
* Specify initializer run order for middleware insertion to avoid frozen middleware stack errors on Rails 8.1+ (@julik)
|
data/README.md
CHANGED
|
@@ -1,347 +1,155 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
end
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
#### Rails Component and Instance Props
|
|
45
|
-
|
|
46
|
-
Starting in version 3.0, Inertia Rails allows you to provide your component name and props via common rails conventions.
|
|
47
|
-
|
|
48
|
-
```ruby
|
|
49
|
-
class EventsController < ApplicationController
|
|
50
|
-
use_inertia_instance_props
|
|
51
|
-
|
|
1
|
+
<div align="center">
|
|
2
|
+
<a href="https://inertia-rails.dev">
|
|
3
|
+
<img src="https://inertia-rails.dev/logo.svg" alt="Inertia Rails" width="150">
|
|
4
|
+
</a>
|
|
5
|
+
|
|
6
|
+
<h1>Build frontend experiences with the backend you love</h1>
|
|
7
|
+
|
|
8
|
+
<p>
|
|
9
|
+
<strong>Single-page React, Vue, and Svelte apps powered by your existing Rails
|
|
10
|
+
controllers, routes, and authentication. No API required.</strong>
|
|
11
|
+
</p>
|
|
12
|
+
|
|
13
|
+
<p>
|
|
14
|
+
<a href="https://rubygems.org/gems/inertia_rails"><img src="https://img.shields.io/gem/v/inertia_rails" alt="Gem version"></a>
|
|
15
|
+
<a href="https://rubygems.org/gems/inertia_rails"><img src="https://img.shields.io/gem/dt/inertia_rails" alt="Downloads"></a>
|
|
16
|
+
<a href="https://github.com/inertiajs/inertia-rails/actions/workflows/push.yml"><img src="https://github.com/inertiajs/inertia-rails/actions/workflows/push.yml/badge.svg" alt="Build status"></a>
|
|
17
|
+
<a href="https://github.com/inertiajs/inertia-rails/blob/master/LICENSE.txt"><img src="https://img.shields.io/badge/license-MIT-blue" alt="MIT license"></a>
|
|
18
|
+
<a href="https://discord.gg/inertiajs"><img src="https://img.shields.io/badge/discord-join-5865F2?logo=discord&logoColor=white" alt="Discord"></a>
|
|
19
|
+
</p>
|
|
20
|
+
|
|
21
|
+
<p>
|
|
22
|
+
<a href="https://inertia-rails.dev"><strong>Documentation</strong></a> ·
|
|
23
|
+
<a href="https://inertia-rails.dev/guide/server-side-setup"><strong>Get started</strong></a> ·
|
|
24
|
+
<a href="https://inertia-rails.dev/guide/demo-application"><strong>Demo</strong></a> ·
|
|
25
|
+
<a href="https://discord.gg/inertiajs"><strong>Discord</strong></a>
|
|
26
|
+
</p>
|
|
27
|
+
</div>
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## Your controllers. Your routes. Modern components.
|
|
32
|
+
|
|
33
|
+
Inertia lets you build a fully client-side rendered single-page app without the
|
|
34
|
+
complexity of a separate API. Pass data from Rails directly to React, Vue, or
|
|
35
|
+
Svelte as **props** — no REST endpoints, no GraphQL, no client-side data
|
|
36
|
+
fetching, no state-management headaches.
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
# app/controllers/users_controller.rb
|
|
40
|
+
class UsersController < ApplicationController
|
|
52
41
|
def index
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
end
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
is the same as
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
```ruby
|
|
63
|
-
class EventsController < ApplicationController
|
|
64
|
-
def index
|
|
65
|
-
render inertia: 'events/index', props: {
|
|
66
|
-
events: Event.all
|
|
42
|
+
render inertia: {
|
|
43
|
+
users: User.active.map { |user| user.as_json(only: [:id, :name, :email]) }
|
|
67
44
|
}
|
|
68
45
|
end
|
|
69
46
|
end
|
|
70
47
|
```
|
|
71
48
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
are automatically disabled for that response. Instance props are only included if they are defined after the before filter is set from `use_inertia_instance_props`.
|
|
49
|
+
```jsx
|
|
50
|
+
// app/frontend/pages/users/index.jsx
|
|
51
|
+
import { Link } from '@inertiajs/react'
|
|
76
52
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
53
|
+
const Users = ({ users }) => (
|
|
54
|
+
<>
|
|
55
|
+
{users.map((user) => (
|
|
56
|
+
<div key={user.id}>
|
|
57
|
+
<Link href={`/users/${user.id}`}>{user.name}</Link>
|
|
58
|
+
<p>{user.email}</p>
|
|
59
|
+
</div>
|
|
60
|
+
))}
|
|
61
|
+
</>
|
|
86
62
|
)
|
|
87
63
|
|
|
64
|
+
export default Users
|
|
88
65
|
```
|
|
89
66
|
|
|
67
|
+
That's the whole loop: the controller returns props, the component renders them.
|
|
68
|
+
Links and form submits are intercepted and turned into XHR visits, so navigation
|
|
69
|
+
feels instant — but you're still writing plain Rails on the server.
|
|
90
70
|
|
|
71
|
+
## Get started
|
|
91
72
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
Inertia layouts use the rails layout convention and can be set or changed in the same way.
|
|
95
|
-
|
|
96
|
-
```ruby
|
|
97
|
-
class EventsController < ApplicationController
|
|
98
|
-
layout 'inertia_application'
|
|
99
|
-
end
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
### Shared Data
|
|
104
|
-
|
|
105
|
-
If you have data that you want to be provided as a prop to every component (a common use-case is information about the authenticated user) you can use the `inertia_share` controller method.
|
|
106
|
-
|
|
107
|
-
```ruby
|
|
108
|
-
class EventsController < ApplicationController
|
|
109
|
-
# share synchronously
|
|
110
|
-
inertia_share app_name: env['app.name']
|
|
111
|
-
|
|
112
|
-
# share lazily, evaluated at render time
|
|
113
|
-
inertia_share do
|
|
114
|
-
if logged_in?
|
|
115
|
-
{
|
|
116
|
-
user: logged_in_user,
|
|
117
|
-
}
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
# share lazily alternate syntax
|
|
122
|
-
inertia_share user_count: lambda { User.count }
|
|
123
|
-
|
|
124
|
-
end
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
#### Deep Merging Shared Data
|
|
128
|
-
|
|
129
|
-
By default, Inertia will shallow merge data defined in an action with the shared data. You might want a deep merge. Imagine using shared data to represent defaults you'll override sometimes.
|
|
130
|
-
|
|
131
|
-
```ruby
|
|
132
|
-
class ApplicationController
|
|
133
|
-
inertia_share do
|
|
134
|
-
{ basketball_data: { points: 50, rebounds: 100 } }
|
|
135
|
-
end
|
|
136
|
-
end
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
Let's say we want a particular action to change only part of that data structure. The renderer accepts a `deep_merge` option:
|
|
140
|
-
|
|
141
|
-
```ruby
|
|
142
|
-
class CrazyScorersController < ApplicationController
|
|
143
|
-
def index
|
|
144
|
-
render inertia: 'CrazyScorersComponent',
|
|
145
|
-
props: { basketball_data: { points: 100 } },
|
|
146
|
-
deep_merge: true
|
|
147
|
-
end
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
# The renderer will send this to the frontend:
|
|
151
|
-
{
|
|
152
|
-
basketball_data: {
|
|
153
|
-
points: 100,
|
|
154
|
-
rebounds: 100,
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
Deep merging can be configured using the [`deep_merge_shared_data`](#deep_merge_shared_data) configuration option.
|
|
160
|
-
|
|
161
|
-
If deep merging is enabled, you can still opt-out within the action:
|
|
162
|
-
|
|
163
|
-
```ruby
|
|
164
|
-
class CrazyScorersController < ApplicationController
|
|
165
|
-
inertia_config(deep_merge_shared_data: true)
|
|
166
|
-
|
|
167
|
-
inertia_share do
|
|
168
|
-
{
|
|
169
|
-
basketball_data: {
|
|
170
|
-
points: 50,
|
|
171
|
-
rebounds: 10,
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
end
|
|
175
|
-
|
|
176
|
-
def index
|
|
177
|
-
render inertia: 'CrazyScorersComponent',
|
|
178
|
-
props: { basketball_data: { points: 100 } },
|
|
179
|
-
deep_merge: false
|
|
180
|
-
end
|
|
181
|
-
end
|
|
73
|
+
**Add to an existing Rails app** — the installer sets up Vite, your chosen framework, and example pages:
|
|
182
74
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
points: 100,
|
|
187
|
-
}
|
|
188
|
-
}
|
|
75
|
+
```bash
|
|
76
|
+
bundle add inertia_rails
|
|
77
|
+
bin/rails generate inertia:install
|
|
189
78
|
```
|
|
190
79
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
On the frontend, Inertia supports the concept of "partial reloads" where only the props requested are returned by the server. Sometimes, you may want to use this flow to avoid processing a particularly slow prop on the initial load. In this case, you can use Optional props. Optional props aren't evaluated unless they're specifically requested by name in a partial reload.
|
|
80
|
+
**Or start from a kit** with authentication, Vite, optional SSR, and Kamal
|
|
81
|
+
deployment already wired up:
|
|
194
82
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
83
|
+
- [React Starter Kit](https://github.com/inertia-rails/react-starter-kit) — React 19 · TypeScript · shadcn/ui
|
|
84
|
+
- [Vue Starter Kit](https://github.com/inertia-rails/vue-starter-kit) — Vue 3 · TypeScript · shadcn-vue
|
|
85
|
+
- [Svelte Starter Kit](https://github.com/inertia-rails/svelte-starter-kit) — Svelte 5 · TypeScript · shadcn-svelte
|
|
198
86
|
|
|
199
|
-
|
|
87
|
+
Full walkthrough: **[Server-side setup](https://inertia-rails.dev/guide/server-side-setup)** and **[Client-side setup](https://inertia-rails.dev/guide/client-side-setup)**.
|
|
200
88
|
|
|
201
|
-
|
|
89
|
+
## Built for real Rails apps
|
|
202
90
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
91
|
+
| | |
|
|
92
|
+
|---|---|
|
|
93
|
+
| **[Forms that work](https://inertia-rails.dev/guide/forms)** | Validation errors flow from Rails to your components automatically — no manual wiring. |
|
|
94
|
+
| **[Server-side rendering](https://inertia-rails.dev/guide/server-side-rendering)** | Full SSR for SEO and fast first paint. Your React/Vue/Svelte, rendered on Rails. |
|
|
95
|
+
| **[Test like Rails](https://inertia-rails.dev/guide/testing)** | RSpec and Minitest matchers that feel native. Assert on props, components, and more. |
|
|
96
|
+
| **[Partial reloads](https://inertia-rails.dev/guide/partial-reloads)** | Refresh only the data you need. Keep interactions snappy without full page loads. |
|
|
97
|
+
| **[Shared data](https://inertia-rails.dev/guide/shared-data)** | Current user, flash, permissions — available on every page automatically. |
|
|
98
|
+
| **[Deferred props](https://inertia-rails.dev/guide/deferred-props)** | Load the page fast, fetch expensive data after, with built-in loading states. |
|
|
99
|
+
| **[Rails generators](https://inertia-rails.dev/guide/server-side-setup)** | Scaffold entire CRUD interfaces — controllers with matching components. |
|
|
100
|
+
| **[History encryption](https://inertia-rails.dev/guide/history-encryption)** | Keep sensitive data private, even in browser history. Toggle per page. |
|
|
206
101
|
|
|
207
|
-
|
|
102
|
+
## Why Inertia?
|
|
208
103
|
|
|
209
|
-
|
|
104
|
+
Inertia sits between traditional server-rendered apps and full SPAs.
|
|
210
105
|
|
|
211
|
-
|
|
106
|
+
**vs. Hotwire** — Same monolith, different view layer. Both keep you in Rails;
|
|
107
|
+
Inertia gives you the full React/Vue/Svelte component model and the npm
|
|
108
|
+
ecosystem instead of HTML-over-the-wire. Choose Hotwire for minimal JS and
|
|
109
|
+
server-rendered HTML; choose Inertia for a modern component architecture.
|
|
212
110
|
|
|
213
|
-
|
|
111
|
+
**vs. API + SPA** — Same frontend, no API hassle. Both give you React/Vue/Svelte,
|
|
112
|
+
but Inertia removes the API layer entirely: one router (Rails), Rails sessions
|
|
113
|
+
instead of a JWT/OAuth dance, and props from your controller instead of fetching
|
|
114
|
+
in `useEffect`. Choose an API for public/mobile clients; choose Inertia for
|
|
115
|
+
focused web products. (You can always add an API alongside Inertia later.)
|
|
214
116
|
|
|
215
|
-
|
|
117
|
+
See the full [comparison and FAQ](https://inertia-rails.dev/#why-inertia) →
|
|
216
118
|
|
|
217
|
-
|
|
119
|
+
## Documentation
|
|
218
120
|
|
|
219
|
-
|
|
121
|
+
Everything lives at **[inertia-rails.dev](https://inertia-rails.dev)**:
|
|
220
122
|
|
|
221
|
-
|
|
222
|
-
|
|
123
|
+
- [How it works](https://inertia-rails.dev/guide/how-it-works)
|
|
124
|
+
- [Pages & layouts](https://inertia-rails.dev/guide/pages)
|
|
125
|
+
- [Forms & validation](https://inertia-rails.dev/guide/forms)
|
|
126
|
+
- [Shared data](https://inertia-rails.dev/guide/shared-data) · [Partial reloads](https://inertia-rails.dev/guide/partial-reloads) · [Deferred props](https://inertia-rails.dev/guide/deferred-props)
|
|
127
|
+
- [Server-side rendering](https://inertia-rails.dev/guide/server-side-rendering)
|
|
128
|
+
- [Testing](https://inertia-rails.dev/guide/testing)
|
|
129
|
+
- [Configuration reference](https://inertia-rails.dev/guide/configuration)
|
|
223
130
|
|
|
224
|
-
|
|
225
|
-
# Example: force a full-reload if the deployed assets change.
|
|
226
|
-
config.version = ViteRuby.digest
|
|
227
|
-
end
|
|
228
|
-
```
|
|
131
|
+
## Community
|
|
229
132
|
|
|
230
|
-
|
|
133
|
+
- [Awesome Inertia Rails](https://inertia-rails.dev/awesome) — gems, tutorials, and real-world apps
|
|
134
|
+
- [Discord](https://discord.gg/inertiajs) — ask questions, get answers fast
|
|
135
|
+
- [GitHub Discussions & Issues](https://github.com/inertiajs/inertia-rails/issues) — browse the source, report bugs
|
|
231
136
|
|
|
232
|
-
|
|
137
|
+
## Contributing
|
|
233
138
|
|
|
234
|
-
|
|
139
|
+
Bug reports and pull requests are welcome. To run the test suite:
|
|
235
140
|
|
|
236
|
-
```
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
version: "events-#{InertiaRails.configuration.version}",
|
|
240
|
-
ssr_enabled: -> { action_name == "index" },
|
|
241
|
-
)
|
|
242
|
-
end
|
|
141
|
+
```bash
|
|
142
|
+
bundle install
|
|
143
|
+
bundle exec rspec
|
|
243
144
|
```
|
|
244
145
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
#### `version` _(recommended)_
|
|
248
|
-
|
|
249
|
-
This allows Inertia to detect if the app running in the client is oudated,
|
|
250
|
-
forcing a full page visit instead of an XHR visit on the next request.
|
|
251
|
-
|
|
252
|
-
See [assets versioning](https://inertiajs.com/asset-versioning).
|
|
253
|
-
|
|
254
|
-
__Default__: `nil`
|
|
255
|
-
|
|
256
|
-
#### `deep_merge_shared_data`
|
|
257
|
-
|
|
258
|
-
When enabled, props will be deep merged with shared data, combining hashes
|
|
259
|
-
with the same keys instead of replacing them.
|
|
260
|
-
|
|
261
|
-
__Default__: `false`
|
|
146
|
+
See the [Code of Conduct](CODE_OF_CONDUCT.md). Everyone interacting with the
|
|
147
|
+
project is expected to follow it.
|
|
262
148
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
Overrides Rails default rendering behavior to render using Inertia by default.
|
|
266
|
-
|
|
267
|
-
__Default__: `false`
|
|
268
|
-
|
|
269
|
-
#### `encrypt_history`
|
|
270
|
-
|
|
271
|
-
When enabled, you instruct Inertia to encrypt your app's history, it uses
|
|
272
|
-
the browser's built-in [`crypto` api](https://developer.mozilla.org/en-US/docs/Web/API/Crypto)
|
|
273
|
-
to encrypt the current page's data before pushing it to the history state.
|
|
274
|
-
|
|
275
|
-
__Default__: `false`
|
|
276
|
-
|
|
277
|
-
#### `ssr_enabled` _(experimental)_
|
|
278
|
-
|
|
279
|
-
Whether to use a JavaScript server to pre-render your JavaScript pages,
|
|
280
|
-
allowing your visitors to receive fully rendered HTML when they first visit
|
|
281
|
-
your application.
|
|
282
|
-
|
|
283
|
-
Requires a JS server to be available at `ssr_url`. [_Example_](https://github.com/ElMassimo/inertia-rails-ssr-template)
|
|
284
|
-
|
|
285
|
-
__Default__: `false`
|
|
286
|
-
|
|
287
|
-
#### `ssr_url` _(experimental)_
|
|
288
|
-
|
|
289
|
-
The URL of the JS server that will pre-render the app using the specified
|
|
290
|
-
component and props.
|
|
291
|
-
|
|
292
|
-
__Default__: `"http://localhost:13714"`
|
|
293
|
-
|
|
294
|
-
## Testing
|
|
295
|
-
|
|
296
|
-
If you're using Rspec, Inertia Rails comes with some nice test helpers to make things simple.
|
|
297
|
-
|
|
298
|
-
To use these helpers, just add the following require statement to your `spec/rails_helper.rb`
|
|
299
|
-
|
|
300
|
-
```ruby
|
|
301
|
-
require 'inertia_rails/rspec'
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
And in any test you want to use the inertia helpers, add the inertia flag to the describe block
|
|
305
|
-
|
|
306
|
-
```ruby
|
|
307
|
-
RSpec.describe EventController, type: :request do
|
|
308
|
-
describe '#index', inertia: true do
|
|
309
|
-
# ...
|
|
310
|
-
end
|
|
311
|
-
end
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
### Assertions
|
|
315
|
-
|
|
316
|
-
```ruby
|
|
317
|
-
RSpec.describe EventController, type: :request do
|
|
318
|
-
describe '#index', inertia: true do
|
|
319
|
-
|
|
320
|
-
# check the component
|
|
321
|
-
expect_inertia.to render_component 'Event/Index'
|
|
322
|
-
|
|
323
|
-
# access the component name
|
|
324
|
-
expect(inertia.component).to eq 'TestComponent'
|
|
325
|
-
|
|
326
|
-
# props (including shared props)
|
|
327
|
-
expect_inertia.to have_exact_props({name: 'Brandon', sport: 'hockey'})
|
|
328
|
-
expect_inertia.to include_props({sport: 'hockey'})
|
|
329
|
-
|
|
330
|
-
# access props
|
|
331
|
-
expect(inertia.props[:name]).to eq 'Brandon'
|
|
332
|
-
|
|
333
|
-
# view data
|
|
334
|
-
expect_inertia.to have_exact_view_data({name: 'Brian', sport: 'basketball'})
|
|
335
|
-
expect_inertia.to include_view_data({sport: 'basketball'})
|
|
336
|
-
|
|
337
|
-
# access view data
|
|
338
|
-
expect(inertia.view_data[:name]).to eq 'Brian'
|
|
339
|
-
|
|
340
|
-
end
|
|
341
|
-
end
|
|
342
|
-
|
|
343
|
-
```
|
|
149
|
+
## Credits
|
|
344
150
|
|
|
345
|
-
|
|
151
|
+
Inertia Rails is part of the official [Inertia.js](https://inertiajs.com)
|
|
152
|
+
organization. It was originally created by the team at
|
|
153
|
+
[bellaWatt](https://bellawatt.com) and is maintained by the Inertia.js community.
|
|
346
154
|
|
|
347
|
-
[
|
|
155
|
+
Released under the [MIT License](LICENSE.txt).
|
|
@@ -142,7 +142,7 @@ module Inertia
|
|
|
142
142
|
def install_typescript
|
|
143
143
|
say 'Adding TypeScript support'
|
|
144
144
|
|
|
145
|
-
add_dependencies(*FRAMEWORKS[framework]['packages_ts'])
|
|
145
|
+
add_dependencies(*FRAMEWORKS[framework]['packages_ts'], dev: true)
|
|
146
146
|
|
|
147
147
|
say 'Copying tsconfig and types'
|
|
148
148
|
|
|
@@ -223,7 +223,8 @@ module Inertia
|
|
|
223
223
|
say_error 'Failed to install Vite Rails gem', :red
|
|
224
224
|
exit(false)
|
|
225
225
|
end
|
|
226
|
-
|
|
226
|
+
vite_ruby_install_options = package_manager.present? ? "--package-manager=#{package_manager.name}" : ''
|
|
227
|
+
if (capture = run("bundle exec vite install #{vite_ruby_install_options}", capture: !verbose?))
|
|
227
228
|
rename_application_js_to_ts if typescript?
|
|
228
229
|
run('bundle binstub vite_ruby', capture: !verbose?) unless File.exist?(file_path('bin/vite'))
|
|
229
230
|
say 'Vite Rails successfully installed', :green
|
|
@@ -282,8 +283,8 @@ module Inertia
|
|
|
282
283
|
@package_manager ||= JSPackageManager.new(self)
|
|
283
284
|
end
|
|
284
285
|
|
|
285
|
-
def add_dependencies(*packages)
|
|
286
|
-
package_manager.add_dependencies(*packages)
|
|
286
|
+
def add_dependencies(*packages, dev: false)
|
|
287
|
+
package_manager.add_dependencies(*packages, dev: dev)
|
|
287
288
|
end
|
|
288
289
|
|
|
289
290
|
def vite_config_path
|
|
@@ -15,10 +15,11 @@ module Inertia
|
|
|
15
15
|
name.present?
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
def add_dependencies(*dependencies)
|
|
18
|
+
def add_dependencies(*dependencies, dev: false)
|
|
19
|
+
dev_flag = dev ? ' -D' : ''
|
|
19
20
|
options = @generator.options[:verbose] ? '' : ' --silent'
|
|
20
21
|
@generator.in_root do
|
|
21
|
-
@generator.run "#{name} add #{dependencies.join(' ')}#{options}"
|
|
22
|
+
@generator.run "#{name} add#{dev_flag} #{dependencies.join(' ')}#{options}"
|
|
22
23
|
end
|
|
23
24
|
end
|
|
24
25
|
|
data/lib/inertia_rails/helper.rb
CHANGED
|
@@ -36,8 +36,14 @@ module InertiaRails
|
|
|
36
36
|
id ||= config.root_dom_id
|
|
37
37
|
|
|
38
38
|
if config.use_script_element_for_initial_page
|
|
39
|
+
script_options = { 'data-page': id, type: 'application/json' }
|
|
40
|
+
if respond_to?(:content_security_policy_nonce, true)
|
|
41
|
+
nonce = content_security_policy_nonce
|
|
42
|
+
script_options[:nonce] = nonce if nonce.present?
|
|
43
|
+
end
|
|
44
|
+
|
|
39
45
|
safe_join([
|
|
40
|
-
tag.script(page.to_json.html_safe,
|
|
46
|
+
tag.script(page.to_json.html_safe, **script_options),
|
|
41
47
|
tag.div(id: id)
|
|
42
48
|
], "\n")
|
|
43
49
|
else
|
|
@@ -24,6 +24,7 @@ module InertiaRails
|
|
|
24
24
|
@_match_on = []
|
|
25
25
|
@_once = {}
|
|
26
26
|
@_scroll = {}
|
|
27
|
+
@_rescued = []
|
|
27
28
|
|
|
28
29
|
props = expand_dot_notation(@props)
|
|
29
30
|
resolved = deep_transform_props(props)
|
|
@@ -71,6 +72,7 @@ module InertiaRails
|
|
|
71
72
|
metadata[:deepMergeProps] = @_deep_merge unless @_deep_merge.empty?
|
|
72
73
|
metadata[:matchPropsOn] = @_match_on unless @_match_on.empty?
|
|
73
74
|
metadata[:onceProps] = @_once unless @_once.empty?
|
|
75
|
+
metadata[:rescuedProps] = @_rescued unless @_rescued.empty?
|
|
74
76
|
|
|
75
77
|
metadata
|
|
76
78
|
end
|
|
@@ -99,29 +101,39 @@ module InertiaRails
|
|
|
99
101
|
collect_metadata(prop, path)
|
|
100
102
|
next unless keep_prop?(prop, path, parent_was_resolved: parent_was_resolved)
|
|
101
103
|
|
|
102
|
-
|
|
104
|
+
rescue_enabled = prop.try(:rescue?)
|
|
103
105
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
collect_metadata(value, path)
|
|
107
|
-
next unless keep_prop?(value, path, parent_was_resolved: parent_was_resolved)
|
|
106
|
+
begin
|
|
107
|
+
value = @evaluator.call(prop)
|
|
108
108
|
|
|
109
|
-
|
|
110
|
-
|
|
109
|
+
# A closure may return a prop type — unwrap one level
|
|
110
|
+
if value.is_a?(BaseProp) && !prop.is_a?(BaseProp)
|
|
111
|
+
collect_metadata(value, path)
|
|
112
|
+
next unless keep_prop?(value, path, parent_was_resolved: parent_was_resolved)
|
|
111
113
|
|
|
112
|
-
|
|
113
|
-
if prop.is_a?(Proc)
|
|
114
|
-
if value.is_a?(Hash) && value.any?
|
|
115
|
-
nested = deep_transform_props(value, path, parent_was_resolved: true)
|
|
116
|
-
transformed_props[key] = nested unless nested.empty?
|
|
117
|
-
next
|
|
118
|
-
elsif value.is_a?(Array)
|
|
119
|
-
transformed_props[key] = transform_array(value, path, parent_was_resolved: true)
|
|
120
|
-
next
|
|
114
|
+
value = @evaluator.call(value)
|
|
121
115
|
end
|
|
122
|
-
end
|
|
123
116
|
|
|
124
|
-
|
|
117
|
+
# A closure may return a Hash or Array containing prop types — recurse into it
|
|
118
|
+
if prop.is_a?(Proc)
|
|
119
|
+
if value.is_a?(Hash) && value.any?
|
|
120
|
+
nested = deep_transform_props(value, path, parent_was_resolved: true)
|
|
121
|
+
transformed_props[key] = nested unless nested.empty?
|
|
122
|
+
next
|
|
123
|
+
elsif value.is_a?(Array)
|
|
124
|
+
transformed_props[key] = transform_array(value, path, parent_was_resolved: true)
|
|
125
|
+
next
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
transformed_props[key] = rescue_enabled ? value.as_json : value
|
|
130
|
+
rescue StandardError => e
|
|
131
|
+
raise unless rescue_enabled
|
|
132
|
+
|
|
133
|
+
report_rescued_error(e)
|
|
134
|
+
@_rescued << path
|
|
135
|
+
next
|
|
136
|
+
end
|
|
125
137
|
end
|
|
126
138
|
end
|
|
127
139
|
|
|
@@ -147,6 +159,16 @@ module InertiaRails
|
|
|
147
159
|
end
|
|
148
160
|
end
|
|
149
161
|
|
|
162
|
+
def report_rescued_error(error)
|
|
163
|
+
# `Rails.error` (the Error Reporter) was introduced in Rails 7.0. Fall back
|
|
164
|
+
# to the logger on older versions so rescued errors are never silently lost.
|
|
165
|
+
if Rails.respond_to?(:error)
|
|
166
|
+
Rails.error.report(error, handled: true)
|
|
167
|
+
else
|
|
168
|
+
Rails.logger&.error("[inertia-rails] Rescued deferred prop error: #{error.class}: #{error.message}")
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
150
172
|
def collect_metadata(prop, path)
|
|
151
173
|
return unless prop.is_a?(BaseProp)
|
|
152
174
|
|