Skip to content

Commit 554f7ec

Browse files
authored
Merge pull request #260 from skryukov/fix-errors-with-partials
Update errors params handling
2 parents f76c284 + f5cb05b commit 554f7ec

File tree

7 files changed

+121
-10
lines changed

7 files changed

+121
-10
lines changed

.rubocop_todo.yml

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# This configuration was generated by
22
# `rubocop --auto-gen-config --exclude-limit 10000`
3-
# on 2025-07-25 08:41:37 UTC using RuboCop version 1.79.0.
3+
# on 2025-08-27 13:50:45 UTC using RuboCop version 1.80.1.
44
# The point is for the user to remove these configuration records
55
# one by one as the offenses are removed from the code base.
66
# Note that changes in the inspected code, or installation of new
@@ -81,14 +81,13 @@ Layout/SpaceInsideBlockBraces:
8181
- 'spec/inertia/error_sharing_spec.rb'
8282
- 'spec/inertia/request_spec.rb'
8383

84-
# Offense count: 56
84+
# Offense count: 54
8585
# This cop supports safe autocorrection (--autocorrect).
8686
# Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces.
8787
# SupportedStyles: space, no_space, compact
8888
# SupportedStylesForEmptyBraces: space, no_space
8989
Layout/SpaceInsideHashLiteralBraces:
9090
Exclude:
91-
- 'lib/inertia_rails/controller.rb'
9291
- 'spec/dummy/app/controllers/inertia_conditional_sharing_controller.rb'
9392
- 'spec/dummy/app/controllers/inertia_share_test_controller.rb'
9493
- 'spec/inertia/conditional_sharing_spec.rb'
@@ -198,7 +197,7 @@ Style/ColonMethodCall:
198197

199198
# Offense count: 1
200199
# This cop supports safe autocorrection (--autocorrect).
201-
# Configuration parameters: AutoCorrect, EnforcedStyle, AllowComments.
200+
# Configuration parameters: EnforcedStyle, AllowComments.
202201
# SupportedStyles: empty, nil, both
203202
Style/EmptyElse:
204203
Exclude:
@@ -212,7 +211,7 @@ Style/EmptyLiteral:
212211

213212
# Offense count: 2
214213
# This cop supports safe autocorrection (--autocorrect).
215-
# Configuration parameters: AutoCorrect, EnforcedStyle.
214+
# Configuration parameters: EnforcedStyle.
216215
# SupportedStyles: compact, expanded
217216
Style/EmptyMethod:
218217
Exclude:
@@ -404,7 +403,7 @@ Style/SoleNestedConditional:
404403
Exclude:
405404
- 'lib/inertia_rails/controller.rb'
406405

407-
# Offense count: 81
406+
# Offense count: 85
408407
# This cop supports safe autocorrection (--autocorrect).
409408
# Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline.
410409
# SupportedStyles: single_quotes, double_quotes
@@ -466,7 +465,7 @@ Style/TrailingCommaInHashLiteral:
466465
- 'spec/inertia/response_spec.rb'
467466
- 'spec/inertia/rspec_helper_spec.rb'
468467

469-
# Offense count: 32
468+
# Offense count: 36
470469
# This cop supports safe autocorrection (--autocorrect).
471470
# Configuration parameters: AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, IgnoreCopDirectives, AllowedPatterns, SplitStrings.
472471
# URISchemes: http, https

docs/guide/configuration.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,19 @@ forcing a full page visit instead of an XHR visit on the next request.
103103

104104
See [assets versioning](/guide/asset-versioning).
105105

106+
### `always_include_errors_hash`
107+
108+
**Default**: `nil`
109+
**ENV**: `INERTIA_ALWAYS_INCLUDE_ERRORS_HASH`
110+
111+
@available_since rails=master
112+
113+
Whether to include an empty `errors` hash in the props when no validation errors are present.
114+
115+
When set to `true`, an empty `errors: {}` object will always be included in Inertia responses. When set to `false`, the `errors` key will be omitted when there are no errors. The default value `nil` currently behaves like `false` but shows a deprecation warning.
116+
117+
The default value will be changed to `true` in the next major version.
118+
106119
### `parent_controller`
107120

108121
**Default**: `'::ApplicationController'`
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# frozen_string_literal: true
22

33
InertiaRails.configure do |config|
4-
config.ssr_enabled = ViteRuby.config.ssr_build_enabled
54
config.version = ViteRuby.digest
5+
config.encrypt_history = true
6+
config.always_include_errors_hash = true
67
end

lib/inertia_rails/configuration.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,11 @@ class Configuration
2626
# Used to detect version drift between server and client.
2727
version: nil,
2828

29-
# Allows configuring the base controller for StaticController
29+
# Allows configuring the base controller for StaticController.
3030
parent_controller: '::ApplicationController',
31+
32+
# Whether to include empty `errors` hash to the props when no errors are present.
33+
always_include_errors_hash: nil,
3134
}.freeze
3235

3336
OPTION_NAMES = DEFAULTS.keys.freeze

lib/inertia_rails/controller.rb

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,22 @@ def inertia_configuration
144144
end
145145

146146
def inertia_shared_data
147-
initial_data = session[:inertia_errors].present? ? {errors: session[:inertia_errors]} : {}
147+
initial_data =
148+
if session[:inertia_errors].present?
149+
{ errors: session[:inertia_errors] }
150+
elsif inertia_configuration.always_include_errors_hash
151+
{ errors: {} }
152+
else
153+
if inertia_configuration.always_include_errors_hash.nil?
154+
InertiaRails.deprecator.warn(
155+
"To comply with the Inertia protocol, an empty errors hash `{errors: {}}` " \
156+
"will be included to all responses by default starting with InertiaRails 4.0. " \
157+
"To opt-in now, set `config.always_include_errors_hash = true`. " \
158+
"To disable this warning, set it to `false`."
159+
)
160+
end
161+
{}
162+
end
148163

149164
self.class._inertia_shared_data.filter_map { |shared_data|
150165
if shared_data.respond_to?(:call)

lib/inertia_rails/renderer.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,11 @@ def merge_props(shared_props, props)
9191

9292
def computed_props
9393
merged_props = merge_props(shared_data, props)
94+
# Always keep errors in the props
95+
if merged_props.key?(:errors) && !merged_props[:errors].is_a?(BaseProp)
96+
errors = merged_props[:errors]
97+
merged_props[:errors] = InertiaRails.always { errors }
98+
end
9499
deep_transform_props(merged_props).tap do |transformed_props|
95100
transformed_props[:_inertia_meta] = meta_tags if meta_tags.present?
96101
end

spec/inertia/error_sharing_spec.rb

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,57 @@
11
RSpec.describe 'errors shared automatically', type: :request do
2+
context 'always_include_errors_hash configuration' do
3+
let(:server_version) { 1.0 }
4+
let(:headers) { { 'X-Inertia' => true } }
5+
6+
after { InertiaRails.configure { |c| c.always_include_errors_hash = nil } }
7+
8+
context 'when always_include_errors_hash is true' do
9+
before { InertiaRails.configure { |c| c.always_include_errors_hash = true } }
10+
11+
it 'includes empty errors hash when no errors present' do
12+
get empty_test_path, headers: headers
13+
expect(response.body).to include({ errors: {} }.to_json)
14+
end
15+
16+
it 'still includes actual errors when they exist' do
17+
post redirect_with_inertia_errors_path, headers: headers
18+
get response.headers['Location'], headers: headers
19+
expect(response.body).to include({ errors: { uh: 'oh' } }.to_json)
20+
end
21+
end
22+
23+
context 'when always_include_errors_hash is false' do
24+
before { InertiaRails.configure { |c| c.always_include_errors_hash = false } }
25+
26+
it 'does not include errors hash when no errors present' do
27+
get empty_test_path, headers: headers
28+
expect(response.body).not_to include('"errors"')
29+
end
30+
31+
it 'still includes actual errors when they exist' do
32+
post redirect_with_inertia_errors_path, headers: headers
33+
get response.headers['Location'], headers: headers
34+
expect(response.body).to include({ errors: { uh: 'oh' } }.to_json)
35+
end
36+
end
37+
38+
context 'when always_include_errors_hash is nil (default)' do
39+
before { InertiaRails.configure { |c| c.always_include_errors_hash = nil } }
40+
41+
it 'shows deprecation warning and does not include empty errors hash' do
42+
expect { get empty_test_path, headers: headers }
43+
.to output(/To comply with the Inertia protocol/).to_stderr
44+
expect(response.body).not_to include('"errors"')
45+
end
46+
47+
it 'still includes actual errors when they exist' do
48+
post redirect_with_inertia_errors_path, headers: headers
49+
get response.headers['Location'], headers: headers
50+
expect(response.body).to include({ errors: { uh: 'oh' } }.to_json)
51+
end
52+
end
53+
end
54+
255
context 'rendering errors across redirects' do
356
let(:server_version){ 1.0 }
457
let(:headers){ { 'X-Inertia' => true, 'X-Inertia-Version' => server_version } }
@@ -45,5 +98,27 @@
4598
expect(response.body).to include(CGI::escape_html({ errors: { uh: 'oh' } }.to_json))
4699
expect(session[:inertia_errors]).not_to be
47100
end
101+
102+
context 'with partial update' do
103+
let(:headers) do
104+
{
105+
'X-Inertia' => true,
106+
'X-Inertia-Version' => server_version,
107+
'X-Inertia-Partial-Component' => 'EmptyTestComponent',
108+
'X-Inertia-Partial-Data' => 'foo',
109+
}
110+
end
111+
112+
it 'keeps errors when partial inertia request redirects' do
113+
post redirect_with_inertia_errors_path, headers: headers
114+
expect(response.headers['Location']).to eq(empty_test_url)
115+
expect(session[:inertia_errors]).to include({ uh: 'oh' })
116+
117+
# Follow the redirect
118+
get response.headers['Location'], headers: headers
119+
expect(response.body).to include({ errors: { uh: 'oh' } }.to_json)
120+
expect(session[:inertia_errors]).not_to be
121+
end
122+
end
48123
end
49124
end

0 commit comments

Comments
 (0)