inertia_rails 3.1.4 → 3.3.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/.gitignore +3 -0
- data/CHANGELOG.md +13 -0
- data/README.md +105 -33
- data/bin/console +7 -8
- data/inertia_rails.gemspec +1 -1
- data/lib/inertia_rails/configuration.rb +90 -0
- data/lib/inertia_rails/controller.rb +48 -16
- data/lib/inertia_rails/helper.rb +8 -1
- data/lib/inertia_rails/inertia_rails.rb +5 -91
- data/lib/inertia_rails/middleware.rb +12 -14
- data/lib/inertia_rails/renderer.rb +44 -22
- data/lib/inertia_rails/rspec.rb +10 -4
- data/lib/inertia_rails/version.rb +1 -1
- data/lib/inertia_rails.rb +4 -0
- metadata +5 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 617a4b404988a934d8bfb0ce176965bec8f09d99dcb167322579152597c75261
|
4
|
+
data.tar.gz: 739e59619439d641ef16dd0816eaab093beb28990624397509a4f1c3b0fc40c6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cc2dcfbdc024ea9a3e83bbd7f0d5afb1be1d14e753d776417f4dbfd7f6bd6e3cdc50e307b73d5495a67b8419ed29b4d2863f467bbf858383504bc7e62920e1ea
|
7
|
+
data.tar.gz: 825b82f4daf26c050c7fe703da03834143a866b2db9728cbb56dface555f4453e984b82038d61bef5e5ce40aa80ef295ef1def1b29794cdc0ef93f6f53a48267
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,19 @@ 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.3.0] - 2024-10-27
|
8
|
+
|
9
|
+
* Refactor Inertia configuration into a controller class method. Thanks @ElMassimo!
|
10
|
+
* Documentation updates. Thanks @osbre and @austenmadden!
|
11
|
+
* Further fixes to the `Vary` header. Thanks @skryukov!
|
12
|
+
* Add configuration option for the component path in the renderer.
|
13
|
+
|
14
|
+
## [3.2.0] - 2024-06-19
|
15
|
+
|
16
|
+
* Refactor the internals of shared Inertia data to use controller instance variables instead of module level variables that run a higher risk of being leaked between requests. Big thanks to @ledermann for the initial work many years ago and to @PedroAugustoRamalhoDuarte for finishing it up!
|
17
|
+
* Change the Inertia response to set the `Vary` header to `X-Inertia` instead of `Accept`, Thanks @osbre!
|
18
|
+
* Always set the `XSRF-TOKEN` in an `after_action` request instead of only on non-Inertia requests. This fixes a bug where logging out (and resetting the session) via Inertia would create a CSRF token mismatch on a subsequent Inertia request (until you manually hard refreshed the page). Thanks @jordanhiltunen!
|
19
|
+
|
7
20
|
## [3.1.4] - 2024-04-28
|
8
21
|
|
9
22
|
* Reset Inertia shared data after each RSpec example where `inertia: true` is used. Thanks @coreyaus!
|
data/README.md
CHANGED
@@ -7,14 +7,26 @@
|
|
7
7
|
|
8
8
|
### Backend
|
9
9
|
|
10
|
-
|
10
|
+
Add the `inertia_rails` gem to your Gemfile.
|
11
|
+
|
11
12
|
```ruby
|
12
13
|
gem 'inertia_rails'
|
13
14
|
```
|
14
15
|
|
16
|
+
For more instructions, see [Server-side setup](https://inertia-rails.netlify.app/guide/server-side-setup.html).
|
17
|
+
|
15
18
|
### Frontend
|
16
19
|
|
17
|
-
|
20
|
+
We are discussing on bringing official docs for Inertia Rails to this repo, as
|
21
|
+
the [official docs](https://inertiajs.com/client-side-setup) are specific to Laravel.
|
22
|
+
|
23
|
+
In the meantime, you can refer to the community-maintained [Client-side setup](https://inertia-rails.netlify.app/guide/client-side-setup.html).
|
24
|
+
|
25
|
+
Examples:
|
26
|
+
|
27
|
+
- [React/Vite](https://github.com/BrandonShar/inertia-rails-template)
|
28
|
+
- [React/Vite + SSR](https://github.com/ElMassimo/inertia-rails-ssr-template)
|
29
|
+
- [PingCRM with Vue and Vite](https://github.com/ledermann/pingcrm)
|
18
30
|
|
19
31
|
## Usage
|
20
32
|
|
@@ -63,12 +75,24 @@ end
|
|
63
75
|
In order to use instance props, you must call `use_inertia_instance_props` on the controller (or a base controller it inherits from). If any props are provided manually, instance props
|
64
76
|
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`.
|
65
77
|
|
66
|
-
Automatic component name is also opt in, you must set the `default_render` config value to `true`. Otherwise, you can simply `render inertia: true` for the same behavior explicitly.
|
78
|
+
Automatic component name is also opt in, you must set the [`default_render`](#default_render) config value to `true`. Otherwise, you can simply `render inertia: true` for the same behavior explicitly.
|
79
|
+
|
80
|
+
If the default component path doesn't match your convention, you can define a method to resolve it however you like via the `component_path_resolver` config value. The value of this should be callable and will receive the path and action and should return a string component path.
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
inertia_config(
|
84
|
+
component_path_resolver: ->(path:, action:) do
|
85
|
+
"Storefront/#{path.camelize}/#{action.camelize}"
|
86
|
+
end
|
87
|
+
)
|
88
|
+
|
89
|
+
```
|
90
|
+
|
91
|
+
|
67
92
|
|
68
93
|
### Layout
|
69
94
|
|
70
|
-
Inertia layouts use the rails layout convention and can be set or changed in the same way.
|
71
|
-
of using rails layouts.
|
95
|
+
Inertia layouts use the rails layout convention and can be set or changed in the same way.
|
72
96
|
|
73
97
|
```ruby
|
74
98
|
class EventsController < ApplicationController
|
@@ -133,20 +157,14 @@ end
|
|
133
157
|
}
|
134
158
|
```
|
135
159
|
|
136
|
-
Deep merging can be
|
160
|
+
Deep merging can be configured using the [`deep_merge_shared_data`](#deep_merge_shared_data) configuration option.
|
137
161
|
|
138
|
-
|
139
|
-
# config/initializers/some_initializer.rb
|
140
|
-
InertiaRails.configure do |config|
|
141
|
-
config.deep_merge_shared_data = true
|
142
|
-
end
|
143
|
-
|
144
|
-
```
|
145
|
-
|
146
|
-
If deep merging is enabled by default, it's possible to opt out within the action:
|
162
|
+
If deep merging is enabled, you can still opt-out within the action:
|
147
163
|
|
148
164
|
```ruby
|
149
165
|
class CrazyScorersController < ApplicationController
|
166
|
+
inertia_config(deep_merge_shared_data: true)
|
167
|
+
|
150
168
|
inertia_share do
|
151
169
|
{
|
152
170
|
basketball_data: {
|
@@ -163,7 +181,7 @@ class CrazyScorersController < ApplicationController
|
|
163
181
|
end
|
164
182
|
end
|
165
183
|
|
166
|
-
#
|
184
|
+
# `deep_merge: false` overrides the default:
|
167
185
|
{
|
168
186
|
basketball_data: {
|
169
187
|
points: 100,
|
@@ -177,6 +195,9 @@ On the front end, Inertia supports the concept of "partial reloads" where only t
|
|
177
195
|
|
178
196
|
```ruby
|
179
197
|
inertia_share some_data: InertiaRails.lazy(lambda { some_very_slow_method })
|
198
|
+
|
199
|
+
# Using a Ruby block syntax
|
200
|
+
inertia_share some_data: InertiaRails.lazy { some_very_slow_method }
|
180
201
|
```
|
181
202
|
|
182
203
|
### Routing
|
@@ -187,34 +208,85 @@ If you don't need a controller to handle a static component, you can route direc
|
|
187
208
|
inertia 'about' => 'AboutComponent'
|
188
209
|
```
|
189
210
|
|
190
|
-
### SSR
|
211
|
+
### SSR _(experimental)_
|
212
|
+
|
213
|
+
Enable SSR via the configuration options for [`ssr_enabled`](#ssr_enabled-experimental) and [`ssr_url`](#ssr_url-experimental).
|
214
|
+
|
215
|
+
When using SSR, don't forget to add `<%= inertia_ssr_head %>` to the `<head>` of your layout (i.e. `application.html.erb`).
|
191
216
|
|
192
|
-
|
217
|
+
## Configuration ⚙️
|
193
218
|
|
194
|
-
|
219
|
+
Inertia Rails can be configured globally or in a specific controller (and subclasses).
|
195
220
|
|
196
|
-
|
221
|
+
### Global Configuration
|
197
222
|
|
198
|
-
|
223
|
+
If using global configuration, we recommend you place the code inside an initializer:
|
199
224
|
|
200
|
-
The default config is shown below
|
201
225
|
```ruby
|
226
|
+
# config/initializers/inertia.rb
|
227
|
+
|
202
228
|
InertiaRails.configure do |config|
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
config.default_render = true
|
208
|
-
|
209
|
-
# ssr specific options
|
210
|
-
config.ssr_enabled = false
|
211
|
-
config.ssr_url = 'http://localhost:13714'
|
229
|
+
# Example: force a full-reload if the deployed assets change.
|
230
|
+
config.version = ViteRuby.digest
|
231
|
+
end
|
232
|
+
```
|
212
233
|
|
213
|
-
|
214
|
-
|
234
|
+
The default configuration can be found [here](https://github.com/inertiajs/inertia-rails/blob/master/lib/inertia_rails/configuration.rb#L5-L22).
|
235
|
+
|
236
|
+
### Local Configuration
|
237
|
+
|
238
|
+
Use `inertia_config` in your controllers to override global settings:
|
239
|
+
|
240
|
+
```ruby
|
241
|
+
class EventsController < ApplicationController
|
242
|
+
inertia_config(
|
243
|
+
version: "events-#{InertiaRails.configuration.version}",
|
244
|
+
ssr_enabled: -> { action_name == "index" },
|
245
|
+
)
|
215
246
|
end
|
216
247
|
```
|
217
248
|
|
249
|
+
### Configuration Options
|
250
|
+
|
251
|
+
#### `version` _(recommended)_
|
252
|
+
|
253
|
+
This allows Inertia to detect if the app running in the client is oudated,
|
254
|
+
forcing a full page visit instead of an XHR visit on the next request.
|
255
|
+
|
256
|
+
See [assets versioning](https://inertiajs.com/asset-versioning).
|
257
|
+
|
258
|
+
__Default__: `nil`
|
259
|
+
|
260
|
+
#### `deep_merge_shared_data`
|
261
|
+
|
262
|
+
When enabled, props will be deep merged with shared data, combining hashes
|
263
|
+
with the same keys instead of replacing them.
|
264
|
+
|
265
|
+
__Default__: `false`
|
266
|
+
|
267
|
+
#### `default_render`
|
268
|
+
|
269
|
+
Overrides Rails default rendering behavior to render using Inertia by default.
|
270
|
+
|
271
|
+
__Default__: `false`
|
272
|
+
|
273
|
+
#### `ssr_enabled` _(experimental)_
|
274
|
+
|
275
|
+
Whether to use a JavaScript server to pre-render your JavaScript pages,
|
276
|
+
allowing your visitors to receive fully rendered HTML when they first visit
|
277
|
+
your application.
|
278
|
+
|
279
|
+
Requires a JS server to be available at `ssr_url`. [_Example_](https://github.com/ElMassimo/inertia-rails-ssr-template)
|
280
|
+
|
281
|
+
__Default__: `false`
|
282
|
+
|
283
|
+
#### `ssr_url` _(experimental)_
|
284
|
+
|
285
|
+
The URL of the JS server that will pre-render the app using the specified
|
286
|
+
component and props.
|
287
|
+
|
288
|
+
__Default__: `"http://localhost:13714"`
|
289
|
+
|
218
290
|
## Testing
|
219
291
|
|
220
292
|
If you're using Rspec, Inertia Rails comes with some nice test helpers to make things simple.
|
data/bin/console
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require "
|
4
|
-
|
5
|
-
|
6
|
-
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
-
# with your gem easier. You can also use a different console, if you like.
|
3
|
+
require "pathname"
|
4
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile",
|
5
|
+
Pathname.new(__FILE__).realpath)
|
8
6
|
|
9
|
-
|
10
|
-
|
11
|
-
|
7
|
+
require "rubygems"
|
8
|
+
require "bundler/setup"
|
9
|
+
require "rails/all"
|
10
|
+
require "inertia_rails"
|
12
11
|
|
13
12
|
require "irb"
|
14
13
|
IRB.start(__FILE__)
|
data/inertia_rails.gemspec
CHANGED
@@ -6,7 +6,7 @@ Gem::Specification.new do |spec|
|
|
6
6
|
spec.name = "inertia_rails"
|
7
7
|
spec.version = InertiaRails::VERSION
|
8
8
|
spec.authors = ["Brian Knoles", "Brandon Shar", "Eugene Granovsky"]
|
9
|
-
spec.email = ["
|
9
|
+
spec.email = ["brian@bellawatt.com", "brandon@bellawatt.com", "eugene@bellawatt.com"]
|
10
10
|
|
11
11
|
spec.summary = %q{Inertia adapter for Rails}
|
12
12
|
spec.homepage = "https://github.com/inertiajs/inertia-rails"
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module InertiaRails
|
4
|
+
class Configuration
|
5
|
+
DEFAULTS = {
|
6
|
+
# Whether to combine hashes with the same keys instead of replacing them.
|
7
|
+
deep_merge_shared_data: false,
|
8
|
+
|
9
|
+
# Overrides Rails default rendering behavior to render using Inertia by default.
|
10
|
+
default_render: false,
|
11
|
+
|
12
|
+
# Allows the user to hook into the default rendering behavior and change it to fit their needs
|
13
|
+
component_path_resolver: ->(path:, action:) { "#{path}/#{action}" },
|
14
|
+
|
15
|
+
# DEPRECATED: Let Rails decide which layout should be used based on the
|
16
|
+
# controller configuration.
|
17
|
+
layout: true,
|
18
|
+
|
19
|
+
# SSR options.
|
20
|
+
ssr_enabled: false,
|
21
|
+
ssr_url: 'http://localhost:13714',
|
22
|
+
|
23
|
+
# Used to detect version drift between server and client.
|
24
|
+
version: nil,
|
25
|
+
}.freeze
|
26
|
+
|
27
|
+
OPTION_NAMES = DEFAULTS.keys.freeze
|
28
|
+
|
29
|
+
protected attr_reader :controller
|
30
|
+
protected attr_reader :options
|
31
|
+
|
32
|
+
def initialize(controller: nil, **attrs)
|
33
|
+
@controller = controller
|
34
|
+
@options = attrs.extract!(*OPTION_NAMES)
|
35
|
+
|
36
|
+
unless attrs.empty?
|
37
|
+
raise ArgumentError, "Unknown options for #{self.class}: #{attrs.keys}"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def bind_controller(controller)
|
42
|
+
Configuration.new(**@options, controller: controller)
|
43
|
+
end
|
44
|
+
|
45
|
+
def freeze
|
46
|
+
@options.freeze
|
47
|
+
super
|
48
|
+
end
|
49
|
+
|
50
|
+
def merge!(config)
|
51
|
+
@options.merge!(config.options)
|
52
|
+
self
|
53
|
+
end
|
54
|
+
|
55
|
+
def merge(config)
|
56
|
+
Configuration.new(**@options.merge(config.options))
|
57
|
+
end
|
58
|
+
|
59
|
+
# Internal: Finalizes the configuration for a specific controller.
|
60
|
+
def with_defaults(config)
|
61
|
+
@options = config.options.merge(@options)
|
62
|
+
freeze
|
63
|
+
end
|
64
|
+
|
65
|
+
def component_path_resolver(path:, action:)
|
66
|
+
@options[:component_path_resolver].call(path:, action:)
|
67
|
+
end
|
68
|
+
|
69
|
+
OPTION_NAMES.each do |option|
|
70
|
+
define_method(option) {
|
71
|
+
evaluate_option @options[option]
|
72
|
+
} unless method_defined?(option)
|
73
|
+
define_method("#{option}=") { |value|
|
74
|
+
@options[option] = value
|
75
|
+
}
|
76
|
+
end
|
77
|
+
|
78
|
+
def self.default
|
79
|
+
new(**DEFAULTS)
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def evaluate_option(value)
|
85
|
+
return value unless value.respond_to?(:call)
|
86
|
+
return value.call unless controller
|
87
|
+
controller.instance_exec(&value)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -6,22 +6,27 @@ module InertiaRails
|
|
6
6
|
extend ActiveSupport::Concern
|
7
7
|
|
8
8
|
included do
|
9
|
-
before_action do
|
10
|
-
# :inertia_errors are deleted from the session by the middleware
|
11
|
-
InertiaRails.share(errors: session[:inertia_errors]) if session[:inertia_errors].present?
|
12
|
-
end
|
13
9
|
helper ::InertiaRails::Helper
|
14
10
|
|
15
11
|
after_action do
|
16
|
-
cookies['XSRF-TOKEN'] = form_authenticity_token
|
12
|
+
cookies['XSRF-TOKEN'] = form_authenticity_token if protect_against_forgery?
|
17
13
|
end
|
18
14
|
end
|
19
15
|
|
20
16
|
module ClassMethods
|
21
|
-
def inertia_share(
|
22
|
-
|
23
|
-
|
24
|
-
|
17
|
+
def inertia_share(attrs = {}, &block)
|
18
|
+
@inertia_share ||= []
|
19
|
+
@inertia_share << attrs.freeze unless attrs.empty?
|
20
|
+
@inertia_share << block if block
|
21
|
+
end
|
22
|
+
|
23
|
+
def inertia_config(**attrs)
|
24
|
+
config = InertiaRails::Configuration.new(**attrs)
|
25
|
+
|
26
|
+
if @inertia_config
|
27
|
+
@inertia_config.merge!(config)
|
28
|
+
else
|
29
|
+
@inertia_config = config
|
25
30
|
end
|
26
31
|
end
|
27
32
|
|
@@ -31,10 +36,29 @@ module InertiaRails
|
|
31
36
|
@_inertia_skip_props = view_assigns.keys + ['_inertia_skip_props']
|
32
37
|
end
|
33
38
|
end
|
39
|
+
|
40
|
+
def _inertia_configuration
|
41
|
+
@_inertia_configuration ||= begin
|
42
|
+
config = superclass.try(:_inertia_configuration) || ::InertiaRails.configuration
|
43
|
+
@inertia_config&.with_defaults(config) || config
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def _inertia_shared_data
|
48
|
+
@_inertia_shared_data ||= begin
|
49
|
+
shared_data = superclass.try(:_inertia_shared_data)
|
50
|
+
|
51
|
+
if @inertia_share && shared_data.present?
|
52
|
+
shared_data + @inertia_share.freeze
|
53
|
+
else
|
54
|
+
@inertia_share || shared_data || []
|
55
|
+
end.freeze
|
56
|
+
end
|
57
|
+
end
|
34
58
|
end
|
35
59
|
|
36
60
|
def default_render
|
37
|
-
if
|
61
|
+
if inertia_configuration.default_render
|
38
62
|
render(inertia: true)
|
39
63
|
else
|
40
64
|
super
|
@@ -55,19 +79,27 @@ module InertiaRails
|
|
55
79
|
)
|
56
80
|
end
|
57
81
|
|
82
|
+
private
|
83
|
+
|
58
84
|
def inertia_view_assigns
|
59
85
|
return {} unless @_inertia_instance_props
|
60
86
|
view_assigns.except(*@_inertia_skip_props)
|
61
87
|
end
|
62
88
|
|
63
|
-
|
89
|
+
def inertia_configuration
|
90
|
+
self.class._inertia_configuration.bind_controller(self)
|
91
|
+
end
|
64
92
|
|
65
|
-
def
|
66
|
-
|
93
|
+
def inertia_shared_data
|
94
|
+
initial_data = session[:inertia_errors].present? ? {errors: session[:inertia_errors]} : {}
|
67
95
|
|
68
|
-
|
69
|
-
|
70
|
-
|
96
|
+
self.class._inertia_shared_data.filter_map { |shared_data|
|
97
|
+
if shared_data.respond_to?(:call)
|
98
|
+
instance_exec(&shared_data)
|
99
|
+
else
|
100
|
+
shared_data
|
101
|
+
end
|
102
|
+
}.reduce(initial_data, &:merge)
|
71
103
|
end
|
72
104
|
|
73
105
|
def inertia_location(url)
|
data/lib/inertia_rails/helper.rb
CHANGED
@@ -1,7 +1,14 @@
|
|
1
1
|
require_relative 'inertia_rails'
|
2
2
|
|
3
3
|
module InertiaRails::Helper
|
4
|
+
def inertia_ssr_head
|
5
|
+
controller.instance_variable_get("@_inertia_ssr_head")
|
6
|
+
end
|
7
|
+
|
4
8
|
def inertia_headers
|
5
|
-
|
9
|
+
InertiaRails.deprecator.warn(
|
10
|
+
"`inertia_headers` is deprecated and will be removed in InertiaRails 4.0, use `inertia_ssr_head` instead."
|
11
|
+
)
|
12
|
+
inertia_ssr_head
|
6
13
|
end
|
7
14
|
end
|
@@ -1,106 +1,20 @@
|
|
1
1
|
# Needed for `thread_mattr_accessor`
|
2
2
|
require 'active_support/core_ext/module/attribute_accessors_per_thread'
|
3
3
|
require 'inertia_rails/lazy'
|
4
|
+
require 'inertia_rails/configuration'
|
4
5
|
|
5
6
|
module InertiaRails
|
6
|
-
|
7
|
-
thread_mattr_accessor :threadsafe_shared_blocks
|
8
|
-
thread_mattr_accessor :threadsafe_html_headers
|
7
|
+
CONFIGURATION = Configuration.default
|
9
8
|
|
10
9
|
def self.configure
|
11
|
-
yield(
|
10
|
+
yield(CONFIGURATION)
|
12
11
|
end
|
13
12
|
|
14
|
-
|
15
|
-
|
16
|
-
shared_plain_data.
|
17
|
-
merge!(evaluated_blocks(controller, shared_blocks))
|
18
|
-
end
|
19
|
-
|
20
|
-
def self.version
|
21
|
-
Configuration.evaluated_version
|
22
|
-
end
|
23
|
-
|
24
|
-
def self.layout
|
25
|
-
Configuration.layout
|
26
|
-
end
|
27
|
-
|
28
|
-
def self.ssr_enabled?
|
29
|
-
Configuration.ssr_enabled
|
30
|
-
end
|
31
|
-
|
32
|
-
def self.ssr_url
|
33
|
-
Configuration.ssr_url
|
34
|
-
end
|
35
|
-
|
36
|
-
def self.default_render?
|
37
|
-
Configuration.default_render
|
38
|
-
end
|
39
|
-
|
40
|
-
def self.html_headers
|
41
|
-
self.threadsafe_html_headers || []
|
42
|
-
end
|
43
|
-
|
44
|
-
def self.deep_merge_shared_data?
|
45
|
-
Configuration.deep_merge_shared_data
|
46
|
-
end
|
47
|
-
|
48
|
-
# "Setters"
|
49
|
-
def self.share(**args)
|
50
|
-
self.shared_plain_data = self.shared_plain_data.merge(args)
|
51
|
-
end
|
52
|
-
|
53
|
-
def self.share_block(block)
|
54
|
-
self.shared_blocks = self.shared_blocks + [block]
|
55
|
-
end
|
56
|
-
|
57
|
-
def self.html_headers=(headers)
|
58
|
-
self.threadsafe_html_headers = headers
|
59
|
-
end
|
60
|
-
|
61
|
-
def self.reset!
|
62
|
-
self.shared_plain_data = {}
|
63
|
-
self.shared_blocks = []
|
64
|
-
self.html_headers = []
|
13
|
+
def self.configuration
|
14
|
+
CONFIGURATION
|
65
15
|
end
|
66
16
|
|
67
17
|
def self.lazy(value = nil, &block)
|
68
18
|
InertiaRails::Lazy.new(value, &block)
|
69
19
|
end
|
70
|
-
|
71
|
-
private
|
72
|
-
|
73
|
-
module Configuration
|
74
|
-
mattr_accessor(:layout) { nil }
|
75
|
-
mattr_accessor(:version) { nil }
|
76
|
-
mattr_accessor(:ssr_enabled) { false }
|
77
|
-
mattr_accessor(:ssr_url) { 'http://localhost:13714' }
|
78
|
-
mattr_accessor(:default_render) { false }
|
79
|
-
mattr_accessor(:deep_merge_shared_data) { false }
|
80
|
-
|
81
|
-
def self.evaluated_version
|
82
|
-
self.version.respond_to?(:call) ? self.version.call : self.version
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
# Getters and setters to provide default values for the threadsafe attributes
|
87
|
-
def self.shared_plain_data
|
88
|
-
self.threadsafe_shared_plain_data || {}
|
89
|
-
end
|
90
|
-
|
91
|
-
def self.shared_plain_data=(val)
|
92
|
-
self.threadsafe_shared_plain_data = val
|
93
|
-
end
|
94
|
-
|
95
|
-
def self.shared_blocks
|
96
|
-
self.threadsafe_shared_blocks || []
|
97
|
-
end
|
98
|
-
|
99
|
-
def self.shared_blocks=(val)
|
100
|
-
self.threadsafe_shared_blocks = val
|
101
|
-
end
|
102
|
-
|
103
|
-
def self.evaluated_blocks(controller, blocks)
|
104
|
-
blocks.flat_map { |block| controller.instance_exec(&block) }.reduce(&:merge) || {}
|
105
|
-
end
|
106
20
|
end
|
@@ -5,10 +5,7 @@ module InertiaRails
|
|
5
5
|
end
|
6
6
|
|
7
7
|
def call(env)
|
8
|
-
InertiaRailsRequest.new(@app, env)
|
9
|
-
.response
|
10
|
-
ensure
|
11
|
-
::InertiaRails.reset!
|
8
|
+
InertiaRailsRequest.new(@app, env).response
|
12
9
|
end
|
13
10
|
|
14
11
|
class InertiaRailsRequest
|
@@ -22,7 +19,7 @@ module InertiaRails
|
|
22
19
|
status, headers, body = @app.call(@env)
|
23
20
|
request = ActionDispatch::Request.new(@env)
|
24
21
|
|
25
|
-
# Inertia errors are added to the session via redirect_to
|
22
|
+
# Inertia errors are added to the session via redirect_to
|
26
23
|
request.session.delete(:inertia_errors) unless keep_inertia_errors?(status)
|
27
24
|
|
28
25
|
status = 303 if inertia_non_post_redirect?(status)
|
@@ -60,11 +57,15 @@ module InertiaRails
|
|
60
57
|
request_method == 'GET'
|
61
58
|
end
|
62
59
|
|
60
|
+
def controller
|
61
|
+
@env["action_controller.instance"]
|
62
|
+
end
|
63
|
+
|
63
64
|
def request_method
|
64
65
|
@env['REQUEST_METHOD']
|
65
66
|
end
|
66
67
|
|
67
|
-
def
|
68
|
+
def client_version
|
68
69
|
@env['HTTP_X_INERTIA_VERSION']
|
69
70
|
end
|
70
71
|
|
@@ -73,17 +74,15 @@ module InertiaRails
|
|
73
74
|
end
|
74
75
|
|
75
76
|
def version_stale?
|
76
|
-
|
77
|
+
coerce_version(client_version) != coerce_version(server_version)
|
77
78
|
end
|
78
79
|
|
79
|
-
def
|
80
|
-
|
81
|
-
|
82
|
-
InertiaRails.version.is_a?(Numeric) ? inertia_version.to_f : inertia_version
|
80
|
+
def server_version
|
81
|
+
controller&.send(:inertia_configuration)&.version
|
83
82
|
end
|
84
83
|
|
85
|
-
def
|
86
|
-
|
84
|
+
def coerce_version(version)
|
85
|
+
server_version.is_a?(Numeric) ? version.to_f : version
|
87
86
|
end
|
88
87
|
|
89
88
|
def force_refresh(request)
|
@@ -97,4 +96,3 @@ module InertiaRails
|
|
97
96
|
end
|
98
97
|
end
|
99
98
|
end
|
100
|
-
|
@@ -4,51 +4,71 @@ require_relative "inertia_rails"
|
|
4
4
|
|
5
5
|
module InertiaRails
|
6
6
|
class Renderer
|
7
|
-
attr_reader
|
7
|
+
attr_reader(
|
8
|
+
:component,
|
9
|
+
:configuration,
|
10
|
+
:controller,
|
11
|
+
:props,
|
12
|
+
:view_data,
|
13
|
+
)
|
8
14
|
|
9
15
|
def initialize(component, controller, request, response, render_method, props: nil, view_data: nil, deep_merge: nil)
|
10
|
-
@component = component.is_a?(TrueClass) ? "#{controller.controller_path}/#{controller.action_name}" : component
|
11
16
|
@controller = controller
|
17
|
+
@configuration = controller.__send__(:inertia_configuration)
|
18
|
+
@component = resolve_component(component)
|
12
19
|
@request = request
|
13
20
|
@response = response
|
14
21
|
@render_method = render_method
|
15
|
-
@props = props
|
22
|
+
@props = props || controller.__send__(:inertia_view_assigns)
|
16
23
|
@view_data = view_data || {}
|
17
|
-
@deep_merge = !deep_merge.nil? ? deep_merge :
|
24
|
+
@deep_merge = !deep_merge.nil? ? deep_merge : configuration.deep_merge_shared_data
|
18
25
|
end
|
19
26
|
|
20
27
|
def render
|
28
|
+
if @response.headers["Vary"].blank?
|
29
|
+
@response.headers["Vary"] = 'X-Inertia'
|
30
|
+
else
|
31
|
+
@response.headers["Vary"] = "#{@response.headers["Vary"]}, X-Inertia"
|
32
|
+
end
|
21
33
|
if @request.headers['X-Inertia']
|
22
|
-
@response.set_header('Vary', 'Accept')
|
23
34
|
@response.set_header('X-Inertia', 'true')
|
24
35
|
@render_method.call json: page, status: @response.status, content_type: Mime[:json]
|
25
36
|
else
|
26
|
-
return render_ssr if
|
27
|
-
@render_method.call template: 'inertia', layout: layout, locals:
|
37
|
+
return render_ssr if configuration.ssr_enabled rescue nil
|
38
|
+
@render_method.call template: 'inertia', layout: layout, locals: view_data.merge(page: page)
|
28
39
|
end
|
29
40
|
end
|
30
41
|
|
31
42
|
private
|
32
43
|
|
33
44
|
def render_ssr
|
34
|
-
uri = URI("#{
|
45
|
+
uri = URI("#{configuration.ssr_url}/render")
|
35
46
|
res = JSON.parse(Net::HTTP.post(uri, page.to_json, 'Content-Type' => 'application/json').body)
|
36
|
-
|
37
|
-
|
38
|
-
@render_method.call html: res['body'].html_safe, layout: layout, locals:
|
47
|
+
|
48
|
+
controller.instance_variable_set("@_inertia_ssr_head", res['head'].join.html_safe)
|
49
|
+
@render_method.call html: res['body'].html_safe, layout: layout, locals: view_data.merge(page: page)
|
39
50
|
end
|
40
51
|
|
41
52
|
def layout
|
42
|
-
|
53
|
+
layout = configuration.layout
|
54
|
+
layout.nil? ? true : layout
|
55
|
+
end
|
56
|
+
|
57
|
+
def shared_data
|
58
|
+
controller.__send__(:inertia_shared_data)
|
59
|
+
end
|
60
|
+
|
61
|
+
# Cast props to symbol keyed hash before merging so that we have a consistent data structure and
|
62
|
+
# avoid duplicate keys after merging.
|
63
|
+
#
|
64
|
+
# Functionally, this permits using either string or symbol keys in the controller. Since the results
|
65
|
+
# is cast to json, we should treat string/symbol keys as identical.
|
66
|
+
def merge_props(shared_data, props)
|
67
|
+
shared_data.deep_symbolize_keys.send(@deep_merge ? :deep_merge : :merge, props.deep_symbolize_keys)
|
43
68
|
end
|
44
69
|
|
45
70
|
def computed_props
|
46
|
-
|
47
|
-
# avoid duplicate keys after merging.
|
48
|
-
#
|
49
|
-
# Functionally, this permits using either string or symbol keys in the controller. Since the results
|
50
|
-
# is cast to json, we should treat string/symbol keys as identical.
|
51
|
-
_props = ::InertiaRails.shared_data(@controller).deep_symbolize_keys.send(prop_merge_method, @props.deep_symbolize_keys).select do |key, prop|
|
71
|
+
_props = merge_props(shared_data, props).select do |key, prop|
|
52
72
|
if rendering_partial_component?
|
53
73
|
key.in? partial_keys
|
54
74
|
else
|
@@ -59,7 +79,7 @@ module InertiaRails
|
|
59
79
|
deep_transform_values(
|
60
80
|
_props,
|
61
81
|
lambda do |prop|
|
62
|
-
prop.respond_to?(:call) ?
|
82
|
+
prop.respond_to?(:call) ? controller.instance_exec(&prop) : prop
|
63
83
|
end
|
64
84
|
)
|
65
85
|
end
|
@@ -69,7 +89,7 @@ module InertiaRails
|
|
69
89
|
component: component,
|
70
90
|
props: computed_props,
|
71
91
|
url: @request.original_fullpath,
|
72
|
-
version:
|
92
|
+
version: configuration.version,
|
73
93
|
}
|
74
94
|
end
|
75
95
|
|
@@ -87,8 +107,10 @@ module InertiaRails
|
|
87
107
|
@request.inertia_partial? && @request.headers['X-Inertia-Partial-Component'] == component
|
88
108
|
end
|
89
109
|
|
90
|
-
def
|
91
|
-
|
110
|
+
def resolve_component(component)
|
111
|
+
return component unless component.is_a? TrueClass
|
112
|
+
|
113
|
+
configuration.component_path_resolver(path: controller.controller_path, action: controller.action_name)
|
92
114
|
end
|
93
115
|
end
|
94
116
|
end
|
data/lib/inertia_rails/rspec.rb
CHANGED
@@ -25,9 +25,16 @@ module InertiaRails
|
|
25
25
|
protected
|
26
26
|
|
27
27
|
def set_values(params)
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
if params[:locals].present?
|
29
|
+
@view_data = params[:locals].except(:page)
|
30
|
+
@props = params[:locals][:page][:props]
|
31
|
+
@component = params[:locals][:page][:component]
|
32
|
+
else
|
33
|
+
# Sequential Inertia request
|
34
|
+
@view_data = {}
|
35
|
+
@props = params[:json][:props]
|
36
|
+
@component = params[:json][:component]
|
37
|
+
end
|
31
38
|
end
|
32
39
|
end
|
33
40
|
|
@@ -65,7 +72,6 @@ RSpec.configure do |config|
|
|
65
72
|
}
|
66
73
|
|
67
74
|
config.before(:each, inertia: true) do
|
68
|
-
::InertiaRails.reset!
|
69
75
|
new_renderer = InertiaRails::Renderer.method(:new)
|
70
76
|
allow(InertiaRails::Renderer).to receive(:new) do |component, controller, request, response, render, named_args|
|
71
77
|
new_renderer.call(component, controller, request, response, inertia_wrap_render(render), **named_args)
|
data/lib/inertia_rails.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: inertia_rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brian Knoles
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: exe
|
12
12
|
cert_chain: []
|
13
|
-
date: 2024-
|
13
|
+
date: 2024-10-27 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: railties
|
@@ -126,7 +126,7 @@ dependencies:
|
|
126
126
|
version: '0'
|
127
127
|
description:
|
128
128
|
email:
|
129
|
-
-
|
129
|
+
- brian@bellawatt.com
|
130
130
|
- brandon@bellawatt.com
|
131
131
|
- eugene@bellawatt.com
|
132
132
|
executables: []
|
@@ -156,6 +156,7 @@ files:
|
|
156
156
|
- lib/generators/inertia_rails/install/vue/inertia.js
|
157
157
|
- lib/generators/inertia_rails/install_generator.rb
|
158
158
|
- lib/inertia_rails.rb
|
159
|
+
- lib/inertia_rails/configuration.rb
|
159
160
|
- lib/inertia_rails/controller.rb
|
160
161
|
- lib/inertia_rails/engine.rb
|
161
162
|
- lib/inertia_rails/helper.rb
|
@@ -194,7 +195,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
194
195
|
- !ruby/object:Gem::Version
|
195
196
|
version: '0'
|
196
197
|
requirements: []
|
197
|
-
rubygems_version: 3.5.
|
198
|
+
rubygems_version: 3.5.10
|
198
199
|
signing_key:
|
199
200
|
specification_version: 4
|
200
201
|
summary: Inertia adapter for Rails
|