inertia_rails 3.9.0 → 3.11.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 +15 -0
- data/app/controllers/inertia_rails/static_controller.rb +3 -1
- data/lib/generators/inertia/install/frameworks.yml +5 -1
- data/lib/generators/inertia/install/templates/initializer.rb +2 -1
- data/lib/generators/inertia/install/templates/svelte/inertia.js +0 -5
- data/lib/generators/inertia/install/templates/svelte/inertia.ts.tt +1 -6
- data/lib/inertia_rails/configuration.rb +11 -1
- data/lib/inertia_rails/controller.rb +21 -1
- data/lib/inertia_rails/defer_prop.rb +3 -2
- data/lib/inertia_rails/generators/controller_template_base.rb +2 -1
- data/lib/inertia_rails/generators/helper.rb +1 -1
- data/lib/inertia_rails/helper.rb +14 -0
- data/lib/inertia_rails/inertia_rails.rb +7 -6
- data/lib/inertia_rails/merge_prop.rb +4 -1
- data/lib/inertia_rails/meta_tag.rb +113 -0
- data/lib/inertia_rails/meta_tag_builder.rb +52 -0
- data/lib/inertia_rails/renderer.rb +47 -20
- data/lib/inertia_rails/rspec.rb +1 -1
- data/lib/inertia_rails/version.rb +1 -1
- data/lib/inertia_rails.rb +1 -5
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 416af24e523dd32daacb768be83fc88bf5465a87adbf49e8105cb630409e45f9
|
4
|
+
data.tar.gz: 4c1d7c883d6ffc3e3239777bd1b1f400f5a0f69c22093a307225d696551b2da5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 23f7eeab79b5e54cc12408f6196f946f5cb5ea78086d55ac56d06827ea0243ba96c90e432e7c69583f7531ae7cd2611a026fdce15039219c36f7ef9034888fa6
|
7
|
+
data.tar.gz: c29f0e2d3c88ebc7a4cc6a405219152a3ae5f4428b23b8ec9a82de8e38e98a52c035d15389c51858b1a6534aae47adef1a26ebd179c4892c7a7b0b76427b88b0
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,21 @@ 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.11.0] - 2025-08-29
|
8
|
+
|
9
|
+
* Fix Svelte generator (@skryukov)
|
10
|
+
* Docs updates for SSR and 2.1.2 (@skryukov)
|
11
|
+
* Devcontainers for local dev (@kieraneglin)
|
12
|
+
* Add configurable prop transformation (@kieraneglin)
|
13
|
+
* Gradual deprecation of null errors because Inertis.js expects an empty object (@skryukov)
|
14
|
+
* Allow the more helpful UnknownFormat exception to raise when a static intertia route is requested with a non-HTML format (@skryukov)
|
15
|
+
|
16
|
+
## [3.10.0] - 2025-07-30
|
17
|
+
|
18
|
+
* llms.txt in docs (@brandonshar and @skryukov)
|
19
|
+
* Add support for deep merging merge props (@skryukov)
|
20
|
+
* Server managed meta tags (@bknoles and @skryukov)
|
21
|
+
|
7
22
|
## [3.9.0] - 2025-06-18
|
8
23
|
|
9
24
|
* Docs updates
|
@@ -4,6 +4,7 @@ react:
|
|
4
4
|
- "@vitejs/plugin-react"
|
5
5
|
- "react"
|
6
6
|
- "react-dom"
|
7
|
+
- "vite@latest"
|
7
8
|
packages_ts:
|
8
9
|
- "@types/react"
|
9
10
|
- "@types/react-dom"
|
@@ -29,6 +30,7 @@ vue:
|
|
29
30
|
packages:
|
30
31
|
- "vue"
|
31
32
|
- "@vitejs/plugin-vue"
|
33
|
+
- "vite@latest"
|
32
34
|
packages_ts:
|
33
35
|
- "typescript@~5.6.2"
|
34
36
|
- "vue-tsc"
|
@@ -52,6 +54,7 @@ svelte4:
|
|
52
54
|
packages:
|
53
55
|
- "svelte@4"
|
54
56
|
- "@sveltejs/vite-plugin-svelte@3"
|
57
|
+
- "vite@5"
|
55
58
|
packages_ts:
|
56
59
|
- "@tsconfig/svelte@4"
|
57
60
|
- "svelte-check"
|
@@ -76,7 +79,8 @@ svelte:
|
|
76
79
|
inertia_package: "@inertiajs/svelte"
|
77
80
|
packages:
|
78
81
|
- "svelte@5"
|
79
|
-
- "@sveltejs/vite-plugin-svelte
|
82
|
+
- "@sveltejs/vite-plugin-svelte"
|
83
|
+
- "vite@latest"
|
80
84
|
packages_ts:
|
81
85
|
- "@tsconfig/svelte@5"
|
82
86
|
- "svelte-check"
|
@@ -2,11 +2,6 @@ import { createInertiaApp } from '@inertiajs/svelte'
|
|
2
2
|
import { mount } from 'svelte';
|
3
3
|
|
4
4
|
createInertiaApp({
|
5
|
-
// Set default page title
|
6
|
-
// see https://inertia-rails.dev/guide/title-and-meta
|
7
|
-
//
|
8
|
-
// title: title => title ? `${title} - App` : 'App',
|
9
|
-
|
10
5
|
// Disable progress bar
|
11
6
|
//
|
12
7
|
// see https://inertia-rails.dev/guide/progress-indicators
|
@@ -2,11 +2,6 @@ import { createInertiaApp, type ResolvedComponent } from '@inertiajs/svelte'
|
|
2
2
|
import { mount } from 'svelte'
|
3
3
|
|
4
4
|
createInertiaApp({
|
5
|
-
// Set default page title
|
6
|
-
// see https://inertia-rails.dev/guide/title-and-meta
|
7
|
-
//
|
8
|
-
// title: title => title ? `${title} - App` : 'App',
|
9
|
-
|
10
5
|
// Disable progress bar
|
11
6
|
//
|
12
7
|
// see https://inertia-rails.dev/guide/progress-indicators
|
@@ -25,7 +20,7 @@ createInertiaApp({
|
|
25
20
|
// and use the following line.
|
26
21
|
// see https://inertia-rails.dev/guide/pages#default-layouts
|
27
22
|
//
|
28
|
-
// return { default: page.default, layout: page.layout || Layout }
|
23
|
+
// return { default: page.default, layout: page.layout || Layout } as ResolvedComponent
|
29
24
|
|
30
25
|
return page
|
31
26
|
},
|
@@ -12,6 +12,9 @@ module InertiaRails
|
|
12
12
|
# Allows the user to hook into the default rendering behavior and change it to fit their needs
|
13
13
|
component_path_resolver: ->(path:, action:) { "#{path}/#{action}" },
|
14
14
|
|
15
|
+
# A function that transforms the props before they are sent to the client.
|
16
|
+
prop_transformer: ->(props:) { props },
|
17
|
+
|
15
18
|
# DEPRECATED: Let Rails decide which layout should be used based on the
|
16
19
|
# controller configuration.
|
17
20
|
layout: true,
|
@@ -26,8 +29,11 @@ module InertiaRails
|
|
26
29
|
# Used to detect version drift between server and client.
|
27
30
|
version: nil,
|
28
31
|
|
29
|
-
# Allows configuring the base controller for StaticController
|
32
|
+
# Allows configuring the base controller for StaticController.
|
30
33
|
parent_controller: '::ApplicationController',
|
34
|
+
|
35
|
+
# Whether to include empty `errors` hash to the props when no errors are present.
|
36
|
+
always_include_errors_hash: nil,
|
31
37
|
}.freeze
|
32
38
|
|
33
39
|
OPTION_NAMES = DEFAULTS.keys.freeze
|
@@ -89,6 +95,10 @@ module InertiaRails
|
|
89
95
|
@options[:component_path_resolver].call(path: path, action: action)
|
90
96
|
end
|
91
97
|
|
98
|
+
def prop_transformer(props:)
|
99
|
+
@options[:prop_transformer].call(props: props)
|
100
|
+
end
|
101
|
+
|
92
102
|
OPTION_NAMES.each do |option|
|
93
103
|
unless method_defined?(option)
|
94
104
|
define_method(option) do
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require_relative "inertia_rails"
|
2
2
|
require_relative "helper"
|
3
3
|
require_relative "action_filter"
|
4
|
+
require_relative "meta_tag_builder"
|
4
5
|
|
5
6
|
module InertiaRails
|
6
7
|
module Controller
|
@@ -127,6 +128,10 @@ module InertiaRails
|
|
127
128
|
super
|
128
129
|
end
|
129
130
|
|
131
|
+
def inertia_meta
|
132
|
+
@inertia_meta ||= InertiaRails::MetaTagBuilder.new(self)
|
133
|
+
end
|
134
|
+
|
130
135
|
private
|
131
136
|
|
132
137
|
def inertia_view_assigns
|
@@ -139,7 +144,22 @@ module InertiaRails
|
|
139
144
|
end
|
140
145
|
|
141
146
|
def inertia_shared_data
|
142
|
-
initial_data =
|
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
|
143
163
|
|
144
164
|
self.class._inertia_shared_data.filter_map { |shared_data|
|
145
165
|
if shared_data.respond_to?(:call)
|
@@ -4,9 +4,9 @@ module InertiaRails
|
|
4
4
|
class DeferProp < IgnoreOnFirstLoadProp
|
5
5
|
DEFAULT_GROUP = 'default'
|
6
6
|
|
7
|
-
attr_reader :group
|
7
|
+
attr_reader :group, :match_on
|
8
8
|
|
9
|
-
def initialize(group: nil, merge: nil, deep_merge: nil, &block)
|
9
|
+
def initialize(group: nil, merge: nil, deep_merge: nil, match_on: nil, &block)
|
10
10
|
raise ArgumentError, 'Cannot set both `deep_merge` and `merge` to true' if deep_merge && merge
|
11
11
|
|
12
12
|
super(&block)
|
@@ -14,6 +14,7 @@ module InertiaRails
|
|
14
14
|
@group = group || DEFAULT_GROUP
|
15
15
|
@merge = merge || deep_merge
|
16
16
|
@deep_merge = deep_merge
|
17
|
+
@match_on = match_on.nil? ? nil : Array(match_on)
|
17
18
|
end
|
18
19
|
|
19
20
|
def merge?
|
@@ -7,11 +7,12 @@ module InertiaRails
|
|
7
7
|
module Generators
|
8
8
|
class ControllerTemplateBase < Rails::Generators::NamedBase
|
9
9
|
include Helper
|
10
|
+
|
10
11
|
class_option :frontend_framework, required: true, desc: 'Frontend framework to generate the views for.',
|
11
12
|
default: Helper.guess_the_default_framework
|
12
13
|
|
13
14
|
class_option :typescript, type: :boolean, desc: 'Whether to use TypeScript',
|
14
|
-
default: Helper.
|
15
|
+
default: Helper.uses_typescript?
|
15
16
|
|
16
17
|
argument :actions, type: :array, default: [], banner: 'action action'
|
17
18
|
|
data/lib/inertia_rails/helper.rb
CHANGED
@@ -15,4 +15,18 @@ module InertiaRails::Helper
|
|
15
15
|
def inertia_rendering?
|
16
16
|
controller.instance_variable_get("@_inertia_rendering")
|
17
17
|
end
|
18
|
+
|
19
|
+
def inertia_page
|
20
|
+
controller.instance_variable_get("@_inertia_page")
|
21
|
+
end
|
22
|
+
|
23
|
+
def inertia_meta_tags
|
24
|
+
meta_tag_data = (inertia_page || {}).dig(:props, :_inertia_meta) || []
|
25
|
+
|
26
|
+
meta_tags = meta_tag_data.map do |inertia_meta_tag|
|
27
|
+
inertia_meta_tag.to_tag(tag)
|
28
|
+
end
|
29
|
+
|
30
|
+
safe_join(meta_tags, "\n")
|
31
|
+
end
|
18
32
|
end
|
@@ -8,6 +8,7 @@ require 'inertia_rails/optional_prop'
|
|
8
8
|
require 'inertia_rails/defer_prop'
|
9
9
|
require 'inertia_rails/merge_prop'
|
10
10
|
require 'inertia_rails/configuration'
|
11
|
+
require 'inertia_rails/meta_tag'
|
11
12
|
|
12
13
|
module InertiaRails
|
13
14
|
class << self
|
@@ -33,16 +34,16 @@ module InertiaRails
|
|
33
34
|
AlwaysProp.new(&block)
|
34
35
|
end
|
35
36
|
|
36
|
-
def merge(&block)
|
37
|
-
MergeProp.new(&block)
|
37
|
+
def merge(match_on: nil, &block)
|
38
|
+
MergeProp.new(match_on: match_on, &block)
|
38
39
|
end
|
39
40
|
|
40
|
-
def deep_merge(&block)
|
41
|
-
MergeProp.new(deep_merge: true, &block)
|
41
|
+
def deep_merge(match_on: nil, &block)
|
42
|
+
MergeProp.new(deep_merge: true, match_on: match_on, &block)
|
42
43
|
end
|
43
44
|
|
44
|
-
def defer(group: nil, merge: nil, deep_merge: nil, &block)
|
45
|
-
DeferProp.new(group: group, merge: merge, deep_merge: deep_merge, &block)
|
45
|
+
def defer(group: nil, merge: nil, deep_merge: nil, match_on: nil, &block)
|
46
|
+
DeferProp.new(group: group, merge: merge, deep_merge: deep_merge, match_on: match_on, &block)
|
46
47
|
end
|
47
48
|
end
|
48
49
|
end
|
@@ -2,9 +2,12 @@
|
|
2
2
|
|
3
3
|
module InertiaRails
|
4
4
|
class MergeProp < BaseProp
|
5
|
-
|
5
|
+
attr_reader :match_on
|
6
|
+
|
7
|
+
def initialize(deep_merge: false, match_on: nil, &block)
|
6
8
|
super(&block)
|
7
9
|
@deep_merge = deep_merge
|
10
|
+
@match_on = match_on.nil? ? nil : Array(match_on)
|
8
11
|
end
|
9
12
|
|
10
13
|
def merge?
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module InertiaRails
|
4
|
+
class MetaTag
|
5
|
+
# See https://github.com/rails/rails/blob/v8.0.0/actionview/lib/action_view/helpers/tag_helper.rb#L84-L97
|
6
|
+
UNARY_TAGS = %i[
|
7
|
+
area base br col embed hr img input keygen link meta source track wbr
|
8
|
+
].freeze
|
9
|
+
|
10
|
+
LD_JSON_TYPE = 'application/ld+json'
|
11
|
+
DEFAULT_SCRIPT_TYPE = 'text/plain'
|
12
|
+
|
13
|
+
GENERATABLE_HEAD_KEY_PROPERTIES = %i[name property http_equiv].freeze
|
14
|
+
|
15
|
+
def initialize(tag_name: nil, head_key: nil, allow_duplicates: false, type: nil, **tag_data)
|
16
|
+
if shortened_title_tag?(tag_name, tag_data)
|
17
|
+
@tag_name = :title
|
18
|
+
@tag_data = { inner_content: tag_data[:title] }
|
19
|
+
else
|
20
|
+
@tag_name = tag_name.nil? ? :meta : tag_name.to_sym
|
21
|
+
@tag_data = tag_data.symbolize_keys
|
22
|
+
end
|
23
|
+
@tag_type = determine_tag_type(type)
|
24
|
+
@allow_duplicates = allow_duplicates
|
25
|
+
@head_key = @tag_name == :title ? 'title' : (head_key || generate_head_key)
|
26
|
+
end
|
27
|
+
|
28
|
+
def as_json(_options = nil)
|
29
|
+
{
|
30
|
+
tagName: @tag_name,
|
31
|
+
headKey: @head_key,
|
32
|
+
type: @tag_type,
|
33
|
+
}.tap do |result|
|
34
|
+
result.merge!(@tag_data.transform_keys { |k| k.to_s.camelize(:lower).to_sym })
|
35
|
+
result.compact_blank!
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_tag(tag_helper)
|
40
|
+
data = @tag_data.merge(type: @tag_type, inertia: @head_key)
|
41
|
+
|
42
|
+
inner_content =
|
43
|
+
if @tag_name == :script
|
44
|
+
tag_script_inner_content(data.delete(:inner_content))
|
45
|
+
else
|
46
|
+
data.delete(:inner_content)
|
47
|
+
end
|
48
|
+
|
49
|
+
if UNARY_TAGS.include? @tag_name
|
50
|
+
tag_helper.public_send(@tag_name, **data.transform_keys { |k| k.to_s.tr('_', '-').to_sym })
|
51
|
+
else
|
52
|
+
tag_helper.public_send(@tag_name, inner_content, **data.transform_keys { |k| k.to_s.tr('_', '-').to_sym })
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def [](key)
|
57
|
+
key = key.to_sym
|
58
|
+
return @tag_name if key == :tag_name
|
59
|
+
return @head_key if key == :head_key
|
60
|
+
return @tag_type if key == :type
|
61
|
+
|
62
|
+
@tag_data[key]
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
|
67
|
+
def tag_script_inner_content(content)
|
68
|
+
case content
|
69
|
+
when Hash, Array
|
70
|
+
ERB::Util.json_escape(content.to_json).html_safe
|
71
|
+
else
|
72
|
+
content
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def shortened_title_tag?(tag_name, tag_data)
|
77
|
+
tag_name.nil? && tag_data.keys == [:title]
|
78
|
+
end
|
79
|
+
|
80
|
+
def determine_tag_type(type)
|
81
|
+
return type unless @tag_name == :script
|
82
|
+
|
83
|
+
type == LD_JSON_TYPE ? LD_JSON_TYPE : DEFAULT_SCRIPT_TYPE
|
84
|
+
end
|
85
|
+
|
86
|
+
def generate_head_key
|
87
|
+
generate_meta_head_key || "#{@tag_name}-#{tag_digest}"
|
88
|
+
end
|
89
|
+
|
90
|
+
def tag_digest
|
91
|
+
signature = @tag_data.sort.map { |k, v| "#{k}=#{v}" }.join('&')
|
92
|
+
Digest::MD5.hexdigest(signature)[0, 8]
|
93
|
+
end
|
94
|
+
|
95
|
+
def generate_meta_head_key
|
96
|
+
return unless @tag_name == :meta
|
97
|
+
return 'meta-charset' if @tag_data.key?(:charset)
|
98
|
+
|
99
|
+
GENERATABLE_HEAD_KEY_PROPERTIES.each do |key|
|
100
|
+
next unless @tag_data.key?(key)
|
101
|
+
|
102
|
+
return [
|
103
|
+
'meta',
|
104
|
+
key,
|
105
|
+
@tag_data[key].parameterize,
|
106
|
+
@allow_duplicates ? tag_digest : nil
|
107
|
+
].compact.join('-')
|
108
|
+
end
|
109
|
+
|
110
|
+
nil
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module InertiaRails
|
4
|
+
class MetaTagBuilder
|
5
|
+
def initialize(controller)
|
6
|
+
@controller = controller
|
7
|
+
@meta_tags = {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def meta_tags
|
11
|
+
@meta_tags.values
|
12
|
+
end
|
13
|
+
|
14
|
+
def add(meta_tag)
|
15
|
+
if meta_tag.is_a?(Array)
|
16
|
+
meta_tag.each { |tag| add(tag) }
|
17
|
+
elsif meta_tag.is_a?(Hash)
|
18
|
+
add_new_tag(meta_tag)
|
19
|
+
else
|
20
|
+
raise ArgumentError, 'Meta tag must be a Hash or Array of Hashes'
|
21
|
+
end
|
22
|
+
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def remove(head_key = nil, &block)
|
27
|
+
raise ArgumentError, 'Cannot provide both head_key and a block' if head_key && block_given?
|
28
|
+
raise ArgumentError, 'Must provide either head_key or a block' if head_key.nil? && !block_given?
|
29
|
+
|
30
|
+
if head_key
|
31
|
+
@meta_tags.delete(head_key)
|
32
|
+
else
|
33
|
+
@meta_tags.reject! { |_, tag| block.call(tag) }
|
34
|
+
end
|
35
|
+
|
36
|
+
self
|
37
|
+
end
|
38
|
+
|
39
|
+
def clear
|
40
|
+
@meta_tags.clear
|
41
|
+
|
42
|
+
self
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def add_new_tag(new_tag_data)
|
48
|
+
new_tag = InertiaRails::MetaTag.new(**new_tag_data)
|
49
|
+
@meta_tags[new_tag[:head_key]] = new_tag
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -16,9 +16,8 @@ module InertiaRails
|
|
16
16
|
:clear_history
|
17
17
|
)
|
18
18
|
|
19
|
-
def initialize(component, controller, request, response, render_method,
|
20
|
-
|
21
|
-
if component.is_a?(Hash) && !props.nil?
|
19
|
+
def initialize(component, controller, request, response, render_method, **options)
|
20
|
+
if component.is_a?(Hash) && options.key?(:props)
|
22
21
|
raise ArgumentError,
|
23
22
|
'Parameter `props` is not allowed when passing a Hash as the first argument'
|
24
23
|
end
|
@@ -29,12 +28,13 @@ module InertiaRails
|
|
29
28
|
@request = request
|
30
29
|
@response = response
|
31
30
|
@render_method = render_method
|
32
|
-
@props = props
|
33
|
-
@view_data = view_data
|
34
|
-
@deep_merge = deep_merge
|
35
|
-
@encrypt_history = encrypt_history
|
36
|
-
@clear_history = clear_history
|
31
|
+
@props = options.fetch(:props, component.is_a?(Hash) ? component : controller.__send__(:inertia_view_assigns))
|
32
|
+
@view_data = options.fetch(:view_data, {})
|
33
|
+
@deep_merge = options.fetch(:deep_merge, configuration.deep_merge_shared_data)
|
34
|
+
@encrypt_history = options.fetch(:encrypt_history, configuration.encrypt_history)
|
35
|
+
@clear_history = options.fetch(:clear_history, controller.session[:inertia_clear_history] || false)
|
37
36
|
@controller.instance_variable_set('@_inertia_rendering', true)
|
37
|
+
controller.inertia_meta.add(options[:meta]) if options[:meta]
|
38
38
|
end
|
39
39
|
|
40
40
|
def render
|
@@ -52,6 +52,7 @@ module InertiaRails
|
|
52
52
|
rescue StandardError
|
53
53
|
nil
|
54
54
|
end
|
55
|
+
controller.instance_variable_set('@_inertia_page', page)
|
55
56
|
@render_method.call template: 'inertia', layout: layout, locals: view_data.merge(page: page)
|
56
57
|
end
|
57
58
|
end
|
@@ -89,8 +90,20 @@ module InertiaRails
|
|
89
90
|
end
|
90
91
|
|
91
92
|
def computed_props
|
92
|
-
|
93
|
-
|
93
|
+
# rubocop:disable Style/MultilineBlockChain
|
94
|
+
merge_props(shared_data, props)
|
95
|
+
.then do |merged_props| # Always keep errors in the props
|
96
|
+
if merged_props.key?(:errors) && !merged_props[:errors].is_a?(BaseProp)
|
97
|
+
errors = merged_props[:errors]
|
98
|
+
merged_props[:errors] = InertiaRails.always { errors }
|
99
|
+
end
|
100
|
+
merged_props
|
101
|
+
end
|
102
|
+
.then { |props| deep_transform_props(props) } # Internal hydration/filtering
|
103
|
+
.then { |props| configuration.prop_transformer(props: props) } # Apply user-defined prop transformer
|
104
|
+
.tap { |props| props[:_inertia_meta] = meta_tags if meta_tags.present? } # Add meta tags last (never transformed)
|
105
|
+
|
106
|
+
# rubocop:enable Style/MultilineBlockChain
|
94
107
|
end
|
95
108
|
|
96
109
|
def page
|
@@ -106,14 +119,17 @@ module InertiaRails
|
|
106
119
|
deferred_props = deferred_props_keys
|
107
120
|
default_page[:deferredProps] = deferred_props if deferred_props.present?
|
108
121
|
|
109
|
-
|
110
|
-
|
111
|
-
deep_merge_props, merge_props = all_merge_props.partition do |key|
|
112
|
-
@props[key].deep_merge?
|
122
|
+
deep_merge_props, merge_props = all_merge_props.partition do |_key, prop|
|
123
|
+
prop.deep_merge?
|
113
124
|
end
|
114
125
|
|
115
|
-
|
116
|
-
|
126
|
+
match_props_on = all_merge_props.filter_map do |key, prop|
|
127
|
+
prop.match_on.map { |ms| "#{key}.#{ms}" } if prop.match_on.present?
|
128
|
+
end.flatten
|
129
|
+
|
130
|
+
default_page[:mergeProps] = merge_props.map(&:first) if merge_props.present?
|
131
|
+
default_page[:deepMergeProps] = deep_merge_props.map(&:first) if deep_merge_props.present?
|
132
|
+
default_page[:matchPropsOn] = match_props_on if match_props_on.present?
|
117
133
|
|
118
134
|
default_page
|
119
135
|
end
|
@@ -147,9 +163,16 @@ module InertiaRails
|
|
147
163
|
end
|
148
164
|
end
|
149
165
|
|
150
|
-
def
|
151
|
-
@props.
|
152
|
-
|
166
|
+
def all_merge_props
|
167
|
+
@all_merge_props ||= @props.select do |key, prop|
|
168
|
+
next unless prop.try(:merge?)
|
169
|
+
next if reset_keys.include?(key)
|
170
|
+
next if rendering_partial_component? && (
|
171
|
+
(partial_keys.present? && partial_keys.exclude?(key.name)) ||
|
172
|
+
(partial_except_keys.present? && partial_except_keys.include?(key.name))
|
173
|
+
)
|
174
|
+
|
175
|
+
true
|
153
176
|
end
|
154
177
|
end
|
155
178
|
|
@@ -180,7 +203,7 @@ module InertiaRails
|
|
180
203
|
def keep_prop?(prop, path)
|
181
204
|
return true if prop.is_a?(AlwaysProp)
|
182
205
|
|
183
|
-
if rendering_partial_component?
|
206
|
+
if rendering_partial_component? && (partial_keys.present? || partial_except_keys.present?)
|
184
207
|
path_with_prefixes = path_prefixes(path)
|
185
208
|
return false if excluded_by_only_partial_keys?(path_with_prefixes)
|
186
209
|
return false if excluded_by_except_partial_keys?(path_with_prefixes)
|
@@ -205,5 +228,9 @@ module InertiaRails
|
|
205
228
|
def excluded_by_except_partial_keys?(path_with_prefixes)
|
206
229
|
partial_except_keys.present? && (path_with_prefixes & partial_except_keys).any?
|
207
230
|
end
|
231
|
+
|
232
|
+
def meta_tags
|
233
|
+
controller.inertia_meta.meta_tags
|
234
|
+
end
|
208
235
|
end
|
209
236
|
end
|
data/lib/inertia_rails/rspec.rb
CHANGED
@@ -75,7 +75,7 @@ RSpec.configure do |config|
|
|
75
75
|
config.before(:each, inertia: true) do
|
76
76
|
new_renderer = InertiaRails::Renderer.method(:new)
|
77
77
|
allow(InertiaRails::Renderer).to receive(:new) do |component, controller, request, response, render, named_args|
|
78
|
-
new_renderer.call(component, controller, request, response, inertia_wrap_render(render), **named_args)
|
78
|
+
new_renderer.call(component, controller, request, response, inertia_wrap_render(render), **(named_args || {}))
|
79
79
|
end
|
80
80
|
end
|
81
81
|
end
|
data/lib/inertia_rails.rb
CHANGED
@@ -15,11 +15,7 @@ ActionController::Renderers.add :inertia do |component, options|
|
|
15
15
|
request,
|
16
16
|
response,
|
17
17
|
method(:render),
|
18
|
-
|
19
|
-
view_data: options[:view_data],
|
20
|
-
deep_merge: options[:deep_merge],
|
21
|
-
encrypt_history: options[:encrypt_history],
|
22
|
-
clear_history: options[:clear_history]
|
18
|
+
**options
|
23
19
|
).render
|
24
20
|
end
|
25
21
|
|
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.11.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-08-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: railties
|
@@ -225,6 +225,8 @@ files:
|
|
225
225
|
- lib/inertia_rails/inertia_rails.rb
|
226
226
|
- lib/inertia_rails/lazy_prop.rb
|
227
227
|
- lib/inertia_rails/merge_prop.rb
|
228
|
+
- lib/inertia_rails/meta_tag.rb
|
229
|
+
- lib/inertia_rails/meta_tag_builder.rb
|
228
230
|
- lib/inertia_rails/middleware.rb
|
229
231
|
- lib/inertia_rails/optional_prop.rb
|
230
232
|
- lib/inertia_rails/renderer.rb
|