inertia_rails 3.14.0 → 3.16.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 +13 -0
- data/app/views/inertia.html.erb +1 -1
- data/lib/generators/inertia/install/helpers.rb +9 -0
- data/lib/generators/inertia/install/install_generator.rb +11 -26
- data/lib/generators/inertia/install/templates/inertia_controller.rb +3 -1
- data/lib/generators/inertia/install/templates/initializer.rb +1 -0
- data/lib/generators/inertia/install/templates/react/InertiaExample.tsx +1 -1
- data/lib/generators/inertia/install/templates/react/inertia.jsx +1 -0
- data/lib/generators/inertia/install/templates/react/inertia.tsx +1 -0
- data/lib/generators/inertia/install/templates/react/types/globals.d.ts +2 -1
- data/lib/generators/inertia/install/templates/react/types/index.ts +2 -4
- data/lib/generators/inertia/install/templates/svelte/inertia.ts +1 -0
- data/lib/generators/inertia/install/templates/svelte/types/globals.d.ts +2 -1
- data/lib/generators/inertia/install/templates/svelte/types/index.ts +2 -4
- data/lib/generators/inertia/install/templates/vue/InertiaExample.ts.vue +1 -1
- data/lib/generators/inertia/install/templates/vue/inertia.ts +1 -0
- data/lib/generators/inertia/install/templates/vue/types/globals.d.ts +2 -1
- data/lib/generators/inertia/install/templates/vue/types/index.ts +2 -4
- data/lib/generators/inertia/scaffold_controller/templates/controller.rb.tt +0 -4
- data/lib/generators/inertia_templates/scaffold/templates/react/index.jsx.tt +4 -2
- data/lib/generators/inertia_templates/scaffold/templates/react/index.tsx.tt +4 -3
- data/lib/generators/inertia_templates/scaffold/templates/react/show.jsx.tt +4 -2
- data/lib/generators/inertia_templates/scaffold/templates/react/show.tsx.tt +4 -3
- data/lib/generators/inertia_templates/scaffold/templates/svelte/index.svelte.tt +4 -4
- data/lib/generators/inertia_templates/scaffold/templates/svelte/index.ts.svelte.tt +4 -5
- data/lib/generators/inertia_templates/scaffold/templates/svelte/show.svelte.tt +4 -4
- data/lib/generators/inertia_templates/scaffold/templates/svelte/show.ts.svelte.tt +4 -5
- data/lib/generators/inertia_templates/scaffold/templates/vue/index.ts.vue.tt +3 -3
- data/lib/generators/inertia_templates/scaffold/templates/vue/index.vue.tt +3 -2
- data/lib/generators/inertia_templates/scaffold/templates/vue/show.ts.vue.tt +3 -3
- data/lib/generators/inertia_templates/scaffold/templates/vue/show.vue.tt +3 -2
- data/lib/generators/inertia_tw_templates/scaffold/templates/react/edit.jsx.tt +4 -4
- data/lib/generators/inertia_tw_templates/scaffold/templates/react/edit.tsx.tt +4 -4
- data/lib/generators/inertia_tw_templates/scaffold/templates/react/index.jsx.tt +4 -2
- data/lib/generators/inertia_tw_templates/scaffold/templates/react/index.tsx.tt +4 -3
- data/lib/generators/inertia_tw_templates/scaffold/templates/react/show.jsx.tt +4 -2
- data/lib/generators/inertia_tw_templates/scaffold/templates/react/show.tsx.tt +4 -3
- data/lib/generators/inertia_tw_templates/scaffold/templates/svelte/index.svelte.tt +4 -4
- data/lib/generators/inertia_tw_templates/scaffold/templates/svelte/index.ts.svelte.tt +4 -5
- data/lib/generators/inertia_tw_templates/scaffold/templates/svelte/show.svelte.tt +4 -4
- data/lib/generators/inertia_tw_templates/scaffold/templates/svelte/show.ts.svelte.tt +4 -5
- data/lib/generators/inertia_tw_templates/scaffold/templates/vue/index.ts.vue.tt +3 -3
- data/lib/generators/inertia_tw_templates/scaffold/templates/vue/index.vue.tt +3 -2
- data/lib/generators/inertia_tw_templates/scaffold/templates/vue/show.ts.vue.tt +3 -3
- data/lib/generators/inertia_tw_templates/scaffold/templates/vue/show.vue.tt +3 -2
- data/lib/inertia_rails/base_prop.rb +1 -1
- data/lib/inertia_rails/configuration.rb +10 -0
- data/lib/inertia_rails/controller.rb +12 -1
- data/lib/inertia_rails/defer_prop.rb +1 -0
- data/lib/inertia_rails/engine.rb +6 -0
- data/lib/inertia_rails/flash_extension.rb +63 -0
- data/lib/inertia_rails/generators/helper.rb +0 -8
- data/lib/inertia_rails/helper.rb +14 -0
- data/lib/inertia_rails/inertia_rails.rb +10 -4
- data/lib/inertia_rails/merge_prop.rb +1 -0
- data/lib/inertia_rails/middleware.rb +1 -1
- data/lib/inertia_rails/once_prop.rb +12 -0
- data/lib/inertia_rails/optional_prop.rb +1 -0
- data/lib/inertia_rails/prop_onceable.rb +39 -0
- data/lib/inertia_rails/renderer.rb +55 -13
- data/lib/inertia_rails/version.rb +1 -1
- data/lib/patches/debug_exceptions.rb +8 -4
- metadata +5 -2
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { Link } from '@inertiajs/svelte'
|
|
2
|
+
import { Link, page } from '@inertiajs/svelte'
|
|
3
3
|
import <%= inertia_component_name %> from './<%= singular_name %>.svelte'
|
|
4
4
|
import type { <%= inertia_model_type %> } from './types'
|
|
5
5
|
|
|
6
|
-
let { <%= plural_table_name
|
|
6
|
+
let { <%= plural_table_name %> } = $props<{
|
|
7
7
|
<%= plural_table_name %>: <%= inertia_model_type %>[]
|
|
8
|
-
flash: { notice?: string }
|
|
9
8
|
}>()
|
|
10
9
|
</script>
|
|
11
10
|
|
|
@@ -14,9 +13,9 @@
|
|
|
14
13
|
</svelte:head>
|
|
15
14
|
|
|
16
15
|
<div class="mx-auto md:w-2/3 w-full px-8 pt-8">
|
|
17
|
-
{#if flash.notice}
|
|
16
|
+
{#if $page.flash.notice}
|
|
18
17
|
<p class="py-2 px-3 bg-green-50 mb-5 text-green-500 font-medium rounded-lg inline-block">
|
|
19
|
-
{flash.notice}
|
|
18
|
+
{$page.flash.notice}
|
|
20
19
|
</p>
|
|
21
20
|
{/if}
|
|
22
21
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<script>
|
|
2
|
-
import { Link } from '@inertiajs/svelte'
|
|
2
|
+
import { Link, page } from '@inertiajs/svelte'
|
|
3
3
|
import <%= inertia_component_name %> from './<%= singular_name %>.svelte'
|
|
4
4
|
|
|
5
|
-
let { <%= singular_table_name
|
|
5
|
+
let { <%= singular_table_name %> } = $props()
|
|
6
6
|
</script>
|
|
7
7
|
|
|
8
8
|
<svelte:head>
|
|
@@ -11,9 +11,9 @@
|
|
|
11
11
|
|
|
12
12
|
<div class="mx-auto md:w-2/3 w-full px-8 pt-8">
|
|
13
13
|
<div class="mx-auto">
|
|
14
|
-
{#if flash.notice}
|
|
14
|
+
{#if $page.flash.notice}
|
|
15
15
|
<p class="py-2 px-3 bg-green-50 mb-5 text-green-500 font-medium rounded-lg inline-block">
|
|
16
|
-
{flash.notice}
|
|
16
|
+
{$page.flash.notice}
|
|
17
17
|
</p>
|
|
18
18
|
{/if}
|
|
19
19
|
|
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { Link } from '@inertiajs/svelte'
|
|
2
|
+
import { Link, page } from '@inertiajs/svelte'
|
|
3
3
|
import <%= inertia_component_name %> from './<%= singular_name %>.svelte'
|
|
4
4
|
import type { <%= inertia_model_type %> } from './types'
|
|
5
5
|
|
|
6
|
-
let { <%= singular_table_name
|
|
6
|
+
let { <%= singular_table_name %> } = $props<{
|
|
7
7
|
<%= singular_table_name %>: <%= inertia_model_type %>
|
|
8
|
-
flash: { notice?: string }
|
|
9
8
|
}>()
|
|
10
9
|
</script>
|
|
11
10
|
|
|
@@ -15,9 +14,9 @@
|
|
|
15
14
|
|
|
16
15
|
<div class="mx-auto md:w-2/3 w-full px-8 pt-8">
|
|
17
16
|
<div class="mx-auto">
|
|
18
|
-
{#if flash.notice}
|
|
17
|
+
{#if $page.flash.notice}
|
|
19
18
|
<p class="py-2 px-3 bg-green-50 mb-5 text-green-500 font-medium rounded-lg inline-block">
|
|
20
|
-
{flash.notice}
|
|
19
|
+
{$page.flash.notice}
|
|
21
20
|
</p>
|
|
22
21
|
{/if}
|
|
23
22
|
|
|
@@ -36,12 +36,12 @@
|
|
|
36
36
|
</template>
|
|
37
37
|
|
|
38
38
|
<script setup lang="ts">
|
|
39
|
-
import { Head, Link } from '@inertiajs/vue3'
|
|
39
|
+
import { Head, Link, usePage } from '@inertiajs/vue3'
|
|
40
40
|
import <%= inertia_component_name %> from './<%= singular_name %>.vue'
|
|
41
41
|
import { <%= inertia_model_type %> } from './types'
|
|
42
42
|
|
|
43
|
-
|
|
43
|
+
defineProps<{
|
|
44
44
|
<%= plural_table_name %>: <%= inertia_model_type %>[]
|
|
45
|
-
flash: { notice?: string }
|
|
46
45
|
}>()
|
|
46
|
+
const { flash } = usePage()
|
|
47
47
|
</script>
|
|
@@ -36,8 +36,9 @@
|
|
|
36
36
|
</template>
|
|
37
37
|
|
|
38
38
|
<script setup>
|
|
39
|
-
import { Head, Link } from '@inertiajs/vue3'
|
|
39
|
+
import { Head, Link, usePage } from '@inertiajs/vue3'
|
|
40
40
|
import <%= inertia_component_name %> from './<%= singular_name %>.vue'
|
|
41
41
|
|
|
42
|
-
|
|
42
|
+
defineProps(['<%= plural_table_name %>'])
|
|
43
|
+
const { flash } = usePage()
|
|
43
44
|
</script>
|
|
@@ -42,12 +42,12 @@
|
|
|
42
42
|
</template>
|
|
43
43
|
|
|
44
44
|
<script setup lang="ts">
|
|
45
|
-
import { Head, Link } from '@inertiajs/vue3'
|
|
45
|
+
import { Head, Link, usePage } from '@inertiajs/vue3'
|
|
46
46
|
import <%= inertia_component_name %> from './<%= singular_name %>.vue'
|
|
47
47
|
import { <%= inertia_model_type %> } from './types'
|
|
48
48
|
|
|
49
|
-
|
|
49
|
+
defineProps<{
|
|
50
50
|
<%= singular_table_name %>: <%= inertia_model_type %>
|
|
51
|
-
flash: { notice?: string }
|
|
52
51
|
}>()
|
|
52
|
+
const { flash } = usePage()
|
|
53
53
|
</script>
|
|
@@ -42,8 +42,9 @@
|
|
|
42
42
|
</template>
|
|
43
43
|
|
|
44
44
|
<script setup>
|
|
45
|
-
import { Head, Link } from '@inertiajs/vue3'
|
|
45
|
+
import { Head, Link, usePage } from '@inertiajs/vue3'
|
|
46
46
|
import <%= inertia_component_name %> from './<%= singular_name %>.vue'
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
defineProps(['<%= singular_table_name %>'])
|
|
49
|
+
const { flash } = usePage()
|
|
49
50
|
</script>
|
|
@@ -34,6 +34,16 @@ module InertiaRails
|
|
|
34
34
|
|
|
35
35
|
# Whether to include empty `errors` hash to the props when no errors are present.
|
|
36
36
|
always_include_errors_hash: nil,
|
|
37
|
+
|
|
38
|
+
# Whether to use `<script>` element for initial page rendering instead of the `data-page` attribute.
|
|
39
|
+
use_script_element_for_initial_page: false,
|
|
40
|
+
|
|
41
|
+
# DOM id to use for the root Inertia.js element.
|
|
42
|
+
root_dom_id: 'app',
|
|
43
|
+
|
|
44
|
+
# Flash keys from Rails flash to expose to frontend.
|
|
45
|
+
# Set to nil to disable Rails flash integration (use only flash.inertia).
|
|
46
|
+
flash_keys: %i[notice alert].freeze,
|
|
37
47
|
}.freeze
|
|
38
48
|
|
|
39
49
|
OPTION_NAMES = DEFAULTS.keys.freeze
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative 'inertia_rails'
|
|
4
|
+
require_relative 'flash_extension'
|
|
4
5
|
require_relative 'helper'
|
|
5
6
|
require_relative 'action_filter'
|
|
6
7
|
require_relative 'meta_tag_builder'
|
|
@@ -180,6 +181,17 @@ module InertiaRails
|
|
|
180
181
|
head :conflict
|
|
181
182
|
end
|
|
182
183
|
|
|
184
|
+
def inertia_collect_flash_data
|
|
185
|
+
flash_data = flash.to_hash
|
|
186
|
+
|
|
187
|
+
allowed_keys = inertia_configuration.flash_keys
|
|
188
|
+
result = allowed_keys ? flash_data.slice(*allowed_keys.map(&:to_s)) : {}
|
|
189
|
+
|
|
190
|
+
result.merge!(flash_data['inertia'].transform_keys(&:to_s)) if flash_data['inertia'].is_a?(Hash)
|
|
191
|
+
|
|
192
|
+
result.symbolize_keys
|
|
193
|
+
end
|
|
194
|
+
|
|
183
195
|
def capture_inertia_session_options(options)
|
|
184
196
|
return unless (inertia = options[:inertia])
|
|
185
197
|
|
|
@@ -192,7 +204,6 @@ module InertiaRails
|
|
|
192
204
|
)
|
|
193
205
|
session[:inertia_errors] = inertia_errors
|
|
194
206
|
end
|
|
195
|
-
|
|
196
207
|
end
|
|
197
208
|
|
|
198
209
|
session[:inertia_clear_history] = inertia[:clear_history] if inertia[:clear_history]
|
data/lib/inertia_rails/engine.rb
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
require_relative 'middleware'
|
|
4
4
|
require_relative 'controller'
|
|
5
|
+
require_relative 'flash_extension'
|
|
5
6
|
|
|
6
7
|
module InertiaRails
|
|
7
8
|
class Engine < ::Rails::Engine
|
|
@@ -14,5 +15,10 @@ module InertiaRails
|
|
|
14
15
|
include ::InertiaRails::Controller
|
|
15
16
|
end
|
|
16
17
|
end
|
|
18
|
+
|
|
19
|
+
initializer 'inertia_rails.flash_extension' do
|
|
20
|
+
ActionDispatch::Flash::FlashHash.prepend ::InertiaRails::FlashExtension
|
|
21
|
+
ActionDispatch::Flash::FlashNow.prepend ::InertiaRails::FlashExtension
|
|
22
|
+
end
|
|
17
23
|
end
|
|
18
24
|
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module InertiaRails
|
|
4
|
+
# Provides a scoped interface for Inertia flash data within Rails' flash.
|
|
5
|
+
# Uses native hash storage: flash[:inertia] = { key: value }
|
|
6
|
+
# Tracks .now keys separately in @inertia_now_keys for session filtering.
|
|
7
|
+
module FlashExtension
|
|
8
|
+
INERTIA_KEY = 'inertia'
|
|
9
|
+
|
|
10
|
+
def inertia
|
|
11
|
+
@inertia ||= InertiaFlashScope.new(self)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# Keys set via flash.now.inertia that should not persist to session
|
|
15
|
+
def inertia_now_keys
|
|
16
|
+
@inertia_now_keys ||= Set.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Clear .now tracking when user explicitly keeps :inertia or all flash
|
|
20
|
+
def keep(key = nil)
|
|
21
|
+
@inertia_now_keys&.clear if key.nil? || key.to_s == INERTIA_KEY
|
|
22
|
+
super
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Override to filter .now keys from nested inertia hash before session persistence
|
|
26
|
+
def to_session_value
|
|
27
|
+
inertia_hash = self[INERTIA_KEY]
|
|
28
|
+
if inertia_hash.is_a?(Hash) && @inertia_now_keys&.any?
|
|
29
|
+
@inertia_now_keys.each { |k| inertia_hash.delete(k.to_s) }
|
|
30
|
+
delete(INERTIA_KEY) if inertia_hash.empty?
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
super
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class InertiaFlashScope
|
|
37
|
+
def initialize(flash_or_now)
|
|
38
|
+
if flash_or_now.respond_to?(:flash)
|
|
39
|
+
@flash = flash_or_now.flash
|
|
40
|
+
@now = true
|
|
41
|
+
else
|
|
42
|
+
@flash = flash_or_now
|
|
43
|
+
@now = false
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def []=(key, value)
|
|
48
|
+
@flash[INERTIA_KEY] ||= {}
|
|
49
|
+
@flash[INERTIA_KEY][key.to_s] = value
|
|
50
|
+
@flash.inertia_now_keys.add(key.to_s) if @now
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def [](key)
|
|
54
|
+
@flash[INERTIA_KEY]&.[](key.to_s)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def to_hash
|
|
58
|
+
@flash[INERTIA_KEY]&.dup || {}
|
|
59
|
+
end
|
|
60
|
+
alias to_h to_hash
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -87,14 +87,6 @@ module InertiaRails
|
|
|
87
87
|
route_url
|
|
88
88
|
end
|
|
89
89
|
|
|
90
|
-
def inertia_js_version
|
|
91
|
-
@inertia_js_version ||= Gem::Version.new(
|
|
92
|
-
JSON.parse(`npm ls @inertiajs/core --json`).then do |json|
|
|
93
|
-
json['dependencies'].values.first['version']
|
|
94
|
-
end
|
|
95
|
-
)
|
|
96
|
-
end
|
|
97
|
-
|
|
98
90
|
def ts_type(attribute)
|
|
99
91
|
case attribute.type
|
|
100
92
|
when :float, :decimal, :integer
|
data/lib/inertia_rails/helper.rb
CHANGED
|
@@ -32,5 +32,19 @@ module InertiaRails
|
|
|
32
32
|
|
|
33
33
|
safe_join(meta_tags, "\n")
|
|
34
34
|
end
|
|
35
|
+
|
|
36
|
+
def inertia_root(id: nil, page: inertia_page)
|
|
37
|
+
config = controller.send(:inertia_configuration)
|
|
38
|
+
id ||= config.root_dom_id
|
|
39
|
+
|
|
40
|
+
if config.use_script_element_for_initial_page
|
|
41
|
+
safe_join([
|
|
42
|
+
tag.script(page.to_json.html_safe, 'data-page': id, type: 'application/json'),
|
|
43
|
+
tag.div(id: id)
|
|
44
|
+
], "\n")
|
|
45
|
+
else
|
|
46
|
+
tag.div(id: id, 'data-page': page.to_json)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
35
49
|
end
|
|
36
50
|
end
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
require 'inertia_rails/prop_onceable'
|
|
3
4
|
require 'inertia_rails/prop_mergeable'
|
|
4
5
|
require 'inertia_rails/base_prop'
|
|
5
6
|
require 'inertia_rails/ignore_on_first_load_prop'
|
|
@@ -8,6 +9,7 @@ require 'inertia_rails/lazy_prop'
|
|
|
8
9
|
require 'inertia_rails/optional_prop'
|
|
9
10
|
require 'inertia_rails/defer_prop'
|
|
10
11
|
require 'inertia_rails/merge_prop'
|
|
12
|
+
require 'inertia_rails/once_prop'
|
|
11
13
|
require 'inertia_rails/scroll_prop'
|
|
12
14
|
require 'inertia_rails/configuration'
|
|
13
15
|
require 'inertia_rails/meta_tag'
|
|
@@ -28,14 +30,18 @@ module InertiaRails
|
|
|
28
30
|
LazyProp.new(value, &block)
|
|
29
31
|
end
|
|
30
32
|
|
|
31
|
-
def optional(
|
|
32
|
-
OptionalProp.new(
|
|
33
|
+
def optional(...)
|
|
34
|
+
OptionalProp.new(...)
|
|
33
35
|
end
|
|
34
36
|
|
|
35
37
|
def always(&block)
|
|
36
38
|
AlwaysProp.new(&block)
|
|
37
39
|
end
|
|
38
40
|
|
|
41
|
+
def once(...)
|
|
42
|
+
OnceProp.new(...)
|
|
43
|
+
end
|
|
44
|
+
|
|
39
45
|
def merge(...)
|
|
40
46
|
MergeProp.new(...)
|
|
41
47
|
end
|
|
@@ -44,8 +50,8 @@ module InertiaRails
|
|
|
44
50
|
MergeProp.new(deep_merge: true, match_on: match_on, &block)
|
|
45
51
|
end
|
|
46
52
|
|
|
47
|
-
def defer(
|
|
48
|
-
DeferProp.new(
|
|
53
|
+
def defer(...)
|
|
54
|
+
DeferProp.new(...)
|
|
49
55
|
end
|
|
50
56
|
|
|
51
57
|
def scroll(metadata = nil, **options, &block)
|
|
@@ -21,7 +21,7 @@ module InertiaRails
|
|
|
21
21
|
status, headers, body = @app.call(@env)
|
|
22
22
|
request = ActionDispatch::Request.new(@env)
|
|
23
23
|
|
|
24
|
-
# Inertia
|
|
24
|
+
# Inertia session data is added via redirect_to
|
|
25
25
|
unless keep_inertia_session_options?(status)
|
|
26
26
|
request.session.delete(:inertia_errors)
|
|
27
27
|
request.session.delete(:inertia_clear_history)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module InertiaRails
|
|
4
|
+
module PropOnceable
|
|
5
|
+
attr_reader :once_key, :once_expires_in
|
|
6
|
+
|
|
7
|
+
def initialize(**props, &block)
|
|
8
|
+
@once = props.fetch(:once, false)
|
|
9
|
+
@once_key = props[:key]
|
|
10
|
+
@once_expires_in = props[:expires_in]
|
|
11
|
+
@fresh = props.fetch(:fresh, false)
|
|
12
|
+
|
|
13
|
+
super
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def once?
|
|
17
|
+
@once
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def fresh?
|
|
21
|
+
@fresh
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def expires_at
|
|
25
|
+
return nil unless @once_expires_in
|
|
26
|
+
|
|
27
|
+
timestamp = case @once_expires_in
|
|
28
|
+
when ActiveSupport::Duration
|
|
29
|
+
(Time.current + @once_expires_in).to_f
|
|
30
|
+
when Numeric
|
|
31
|
+
Time.current.to_f + @once_expires_in
|
|
32
|
+
else
|
|
33
|
+
raise ArgumentError, "Invalid `expires_in` value: #{@once_expires_in.inspect}"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
(timestamp * 1000).to_i
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -48,7 +48,7 @@ module InertiaRails
|
|
|
48
48
|
else
|
|
49
49
|
"#{@response.headers['Vary']}, X-Inertia"
|
|
50
50
|
end
|
|
51
|
-
if @request.
|
|
51
|
+
if @request.inertia?
|
|
52
52
|
@response.set_header('X-Inertia', 'true')
|
|
53
53
|
@render_method.call json: page.to_json, status: @response.status, content_type: Mime[:json]
|
|
54
54
|
else
|
|
@@ -97,15 +97,17 @@ module InertiaRails
|
|
|
97
97
|
def computed_props
|
|
98
98
|
# rubocop:disable Style/MultilineBlockChain
|
|
99
99
|
@props
|
|
100
|
-
.tap do |merged_props|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
100
|
+
.tap do |merged_props|
|
|
101
|
+
# Always keep errors in the props
|
|
102
|
+
if merged_props.key?(:errors) && !merged_props[:errors].is_a?(BaseProp)
|
|
103
|
+
errors = merged_props[:errors]
|
|
104
|
+
merged_props[:errors] = InertiaRails.always { errors }
|
|
105
105
|
end
|
|
106
|
+
end
|
|
106
107
|
.then { |props| deep_transform_props(props) } # Internal hydration/filtering
|
|
107
108
|
.then { |props| @configuration.prop_transformer(props: props) } # Apply user-defined prop transformer
|
|
108
|
-
.tap do |props|
|
|
109
|
+
.tap do |props|
|
|
110
|
+
# Add meta tags last (never transformed)
|
|
109
111
|
props[:_inertia_meta] = meta_tags if meta_tags.present?
|
|
110
112
|
end
|
|
111
113
|
# rubocop:enable Style/MultilineBlockChain
|
|
@@ -123,11 +125,17 @@ module InertiaRails
|
|
|
123
125
|
clearHistory: @clear_history,
|
|
124
126
|
}
|
|
125
127
|
|
|
128
|
+
flash_data = @controller.__send__(:inertia_collect_flash_data)
|
|
129
|
+
@page[:flash] = flash_data if flash_data.present?
|
|
130
|
+
|
|
126
131
|
deferred_props = deferred_props_keys
|
|
127
132
|
@page[:deferredProps] = deferred_props if deferred_props.present?
|
|
128
133
|
@page[:scrollProps] = scroll_props if scroll_props.present?
|
|
129
134
|
@page.merge!(resolve_merge_props)
|
|
130
135
|
|
|
136
|
+
once_props = resolve_once_props
|
|
137
|
+
@page[:onceProps] = once_props if once_props.present?
|
|
138
|
+
|
|
131
139
|
@page
|
|
132
140
|
end
|
|
133
141
|
|
|
@@ -173,6 +181,17 @@ module InertiaRails
|
|
|
173
181
|
}.delete_if { |_, v| v.blank? }
|
|
174
182
|
end
|
|
175
183
|
|
|
184
|
+
def resolve_once_props
|
|
185
|
+
@props.each_with_object({}) do |(key, prop), result|
|
|
186
|
+
next unless prop.try(:once?)
|
|
187
|
+
next if excluded_by_partial_request?([key.to_s])
|
|
188
|
+
|
|
189
|
+
once_key = (prop.once_key || key).to_s
|
|
190
|
+
|
|
191
|
+
result[once_key] = { prop: key.to_s, expiresAt: prop.expires_at }.compact
|
|
192
|
+
end
|
|
193
|
+
end
|
|
194
|
+
|
|
176
195
|
def resolve_match_on_props
|
|
177
196
|
all_merge_props.filter_map do |key, prop|
|
|
178
197
|
prop.match_on.map! { |ms| "#{key}.#{ms}" } if prop.match_on.present?
|
|
@@ -251,6 +270,10 @@ module InertiaRails
|
|
|
251
270
|
@partial_except_keys ||= (@request.headers['X-Inertia-Partial-Except'] || '').split(',').compact_blank!
|
|
252
271
|
end
|
|
253
272
|
|
|
273
|
+
def except_once_keys
|
|
274
|
+
@except_once_keys ||= (@request.headers['X-Inertia-Except-Once-Props'] || '').split(',').compact_blank!
|
|
275
|
+
end
|
|
276
|
+
|
|
254
277
|
def rendering_partial_component?
|
|
255
278
|
@request.headers['X-Inertia-Partial-Component'] == @component
|
|
256
279
|
end
|
|
@@ -265,12 +288,8 @@ module InertiaRails
|
|
|
265
288
|
|
|
266
289
|
def keep_prop?(prop, path)
|
|
267
290
|
return true if prop.is_a?(AlwaysProp)
|
|
268
|
-
|
|
269
|
-
if
|
|
270
|
-
path_with_prefixes = path_prefixes(path)
|
|
271
|
-
return false if excluded_by_only_partial_keys?(path_with_prefixes)
|
|
272
|
-
return false if excluded_by_except_partial_keys?(path_with_prefixes)
|
|
273
|
-
end
|
|
291
|
+
return false if excluded_by_once_cache?(prop, path)
|
|
292
|
+
return false if excluded_by_partial_request?(path)
|
|
274
293
|
|
|
275
294
|
# Precedence: Evaluate IgnoreOnFirstLoadProp only after partial keys have been checked
|
|
276
295
|
return false if prop.is_a?(IgnoreOnFirstLoadProp) && !rendering_partial_component?
|
|
@@ -278,6 +297,29 @@ module InertiaRails
|
|
|
278
297
|
true
|
|
279
298
|
end
|
|
280
299
|
|
|
300
|
+
def excluded_by_once_cache?(prop, path)
|
|
301
|
+
return false unless prop.try(:once?)
|
|
302
|
+
return false if prop.try(:fresh?)
|
|
303
|
+
return false if explicitly_requested?(path)
|
|
304
|
+
|
|
305
|
+
once_key = (prop.once_key || path.join('.')).to_s
|
|
306
|
+
except_once_keys.include?(once_key)
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
def explicitly_requested?(path)
|
|
310
|
+
return false unless rendering_partial_component? && partial_keys.present?
|
|
311
|
+
|
|
312
|
+
path_with_prefixes = path_prefixes(path)
|
|
313
|
+
(path_with_prefixes & partial_keys).any?
|
|
314
|
+
end
|
|
315
|
+
|
|
316
|
+
def excluded_by_partial_request?(path)
|
|
317
|
+
return false unless rendering_partial_component? && (partial_keys.present? || partial_except_keys.present?)
|
|
318
|
+
|
|
319
|
+
path_with_prefixes = path_prefixes(path)
|
|
320
|
+
excluded_by_only_partial_keys?(path_with_prefixes) || excluded_by_except_partial_keys?(path_with_prefixes)
|
|
321
|
+
end
|
|
322
|
+
|
|
281
323
|
def path_prefixes(parts)
|
|
282
324
|
(0...parts.length).map do |i|
|
|
283
325
|
parts[0..i].join('.')
|
|
@@ -5,18 +5,22 @@
|
|
|
5
5
|
# The original source needs to be patched, so that Inertia requests are
|
|
6
6
|
# NOT responded with plain text, but with HTML.
|
|
7
7
|
#
|
|
8
|
-
# Original source
|
|
9
|
-
# https://github.com/rails/rails/blob/5-1-stable/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
|
|
8
|
+
# Original source:
|
|
10
9
|
# https://github.com/rails/rails/blob/8-0-stable/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
|
|
10
|
+
# https://github.com/rails/rails/blob/main/actionpack/lib/action_dispatch/middleware/debug_exceptions.rb
|
|
11
11
|
#
|
|
12
12
|
|
|
13
13
|
module InertiaRails
|
|
14
14
|
module InertiaDebugExceptions
|
|
15
|
-
|
|
15
|
+
# Rails 8.2+ passes content_type as third argument
|
|
16
|
+
def render_for_browser_request(request, wrapper, content_type = nil)
|
|
16
17
|
template = create_template(request, wrapper)
|
|
17
18
|
file = "rescues/#{wrapper.rescue_template}"
|
|
18
19
|
|
|
19
|
-
if
|
|
20
|
+
if content_type == Mime[:md]
|
|
21
|
+
body = template.render(template: file, layout: false, formats: [:text])
|
|
22
|
+
format = 'text/markdown'
|
|
23
|
+
elsif request.xhr? && !request.headers['X-Inertia']
|
|
20
24
|
body = template.render(template: file, layout: false, formats: [:text])
|
|
21
25
|
format = 'text/plain'
|
|
22
26
|
else
|
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.16.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Brian Knoles
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
- Eugene Granovsky
|
|
10
10
|
bindir: bin
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2025-
|
|
12
|
+
date: 2025-12-30 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: railties
|
|
@@ -189,6 +189,7 @@ files:
|
|
|
189
189
|
- lib/inertia_rails/controller.rb
|
|
190
190
|
- lib/inertia_rails/defer_prop.rb
|
|
191
191
|
- lib/inertia_rails/engine.rb
|
|
192
|
+
- lib/inertia_rails/flash_extension.rb
|
|
192
193
|
- lib/inertia_rails/generators/controller_template_base.rb
|
|
193
194
|
- lib/inertia_rails/generators/helper.rb
|
|
194
195
|
- lib/inertia_rails/generators/scaffold_template_base.rb
|
|
@@ -200,8 +201,10 @@ files:
|
|
|
200
201
|
- lib/inertia_rails/meta_tag.rb
|
|
201
202
|
- lib/inertia_rails/meta_tag_builder.rb
|
|
202
203
|
- lib/inertia_rails/middleware.rb
|
|
204
|
+
- lib/inertia_rails/once_prop.rb
|
|
203
205
|
- lib/inertia_rails/optional_prop.rb
|
|
204
206
|
- lib/inertia_rails/prop_mergeable.rb
|
|
207
|
+
- lib/inertia_rails/prop_onceable.rb
|
|
205
208
|
- lib/inertia_rails/renderer.rb
|
|
206
209
|
- lib/inertia_rails/rspec.rb
|
|
207
210
|
- lib/inertia_rails/scroll_metadata.rb
|