inertia_rails 3.13.0 → 3.15.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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -0
  3. data/app/views/inertia.html.erb +1 -1
  4. data/lib/generators/inertia/install/frameworks.yml +3 -18
  5. data/lib/generators/inertia/install/install_generator.rb +51 -6
  6. data/lib/generators/inertia/install/templates/assets/rails.svg +9 -0
  7. data/lib/generators/inertia/install/templates/controller.rb +6 -1
  8. data/lib/generators/inertia/install/templates/initializer.rb +1 -0
  9. data/lib/generators/inertia/install/templates/react/InertiaExample.jsx +42 -46
  10. data/lib/generators/inertia/install/templates/react/InertiaExample.module.css +63 -41
  11. data/lib/generators/inertia/install/templates/react/InertiaExample.tsx +45 -46
  12. data/lib/generators/inertia/install/templates/react/inertia.jsx +2 -1
  13. data/lib/generators/inertia/install/templates/react/inertia.tsx +4 -3
  14. data/lib/generators/inertia/install/templates/svelte/InertiaExample.svelte +103 -69
  15. data/lib/generators/inertia/install/templates/svelte/InertiaExample.ts.svelte +104 -69
  16. data/lib/generators/inertia/install/templates/svelte/inertia.js +1 -1
  17. data/lib/generators/inertia/install/templates/svelte/inertia.ts +2 -1
  18. data/lib/generators/inertia/install/templates/vue/InertiaExample.ts.vue +107 -70
  19. data/lib/generators/inertia/install/templates/vue/InertiaExample.vue +129 -92
  20. data/lib/generators/inertia/install/templates/vue/inertia.js +3 -3
  21. data/lib/generators/inertia/install/templates/vue/inertia.ts +4 -3
  22. data/lib/generators/inertia_templates/scaffold/templates/react/form.tsx.tt +3 -3
  23. data/lib/generators/inertia_templates/scaffold/templates/svelte/form.ts.svelte.tt +3 -3
  24. data/lib/generators/inertia_templates/scaffold/templates/svelte/new.svelte.tt +1 -1
  25. data/lib/generators/inertia_templates/scaffold/templates/svelte/new.ts.svelte.tt +1 -1
  26. data/lib/generators/inertia_templates/scaffold/templates/vue/form.ts.vue.tt +3 -3
  27. data/lib/generators/inertia_tw_templates/scaffold/templates/react/form.tsx.tt +3 -3
  28. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte/form.ts.svelte.tt +3 -3
  29. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte/new.svelte.tt +1 -2
  30. data/lib/generators/inertia_tw_templates/scaffold/templates/svelte/new.ts.svelte.tt +1 -1
  31. data/lib/generators/inertia_tw_templates/scaffold/templates/vue/form.ts.vue.tt +3 -3
  32. data/lib/inertia_rails/base_prop.rb +1 -1
  33. data/lib/inertia_rails/configuration.rb +6 -0
  34. data/lib/inertia_rails/defer_prop.rb +1 -0
  35. data/lib/inertia_rails/helper.rb +14 -0
  36. data/lib/inertia_rails/inertia_rails.rb +8 -2
  37. data/lib/inertia_rails/merge_prop.rb +1 -0
  38. data/lib/inertia_rails/once_prop.rb +12 -0
  39. data/lib/inertia_rails/optional_prop.rb +1 -0
  40. data/lib/inertia_rails/prop_onceable.rb +39 -0
  41. data/lib/inertia_rails/renderer.rb +52 -13
  42. data/lib/inertia_rails/version.rb +1 -1
  43. data/lib/inertia_rails.rb +1 -0
  44. metadata +5 -2
@@ -48,7 +48,7 @@ module InertiaRails
48
48
  else
49
49
  "#{@response.headers['Vary']}, X-Inertia"
50
50
  end
51
- if @request.headers['X-Inertia']
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| # Always keep errors in the props
101
- if merged_props.key?(:errors) && !merged_props[:errors].is_a?(BaseProp)
102
- errors = merged_props[:errors]
103
- merged_props[:errors] = InertiaRails.always { errors }
104
- end
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| # Add meta tags last (never transformed)
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
@@ -128,6 +130,9 @@ module InertiaRails
128
130
  @page[:scrollProps] = scroll_props if scroll_props.present?
129
131
  @page.merge!(resolve_merge_props)
130
132
 
133
+ once_props = resolve_once_props
134
+ @page[:onceProps] = once_props if once_props.present?
135
+
131
136
  @page
132
137
  end
133
138
 
@@ -173,6 +178,17 @@ module InertiaRails
173
178
  }.delete_if { |_, v| v.blank? }
174
179
  end
175
180
 
181
+ def resolve_once_props
182
+ @props.each_with_object({}) do |(key, prop), result|
183
+ next unless prop.try(:once?)
184
+ next if excluded_by_partial_request?([key.to_s])
185
+
186
+ once_key = (prop.once_key || key).to_s
187
+
188
+ result[once_key] = { prop: key.to_s, expiresAt: prop.expires_at }.compact
189
+ end
190
+ end
191
+
176
192
  def resolve_match_on_props
177
193
  all_merge_props.filter_map do |key, prop|
178
194
  prop.match_on.map! { |ms| "#{key}.#{ms}" } if prop.match_on.present?
@@ -251,6 +267,10 @@ module InertiaRails
251
267
  @partial_except_keys ||= (@request.headers['X-Inertia-Partial-Except'] || '').split(',').compact_blank!
252
268
  end
253
269
 
270
+ def except_once_keys
271
+ @except_once_keys ||= (@request.headers['X-Inertia-Except-Once-Props'] || '').split(',').compact_blank!
272
+ end
273
+
254
274
  def rendering_partial_component?
255
275
  @request.headers['X-Inertia-Partial-Component'] == @component
256
276
  end
@@ -265,12 +285,8 @@ module InertiaRails
265
285
 
266
286
  def keep_prop?(prop, path)
267
287
  return true if prop.is_a?(AlwaysProp)
268
-
269
- if rendering_partial_component? && (partial_keys.present? || partial_except_keys.present?)
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
288
+ return false if excluded_by_once_cache?(prop, path)
289
+ return false if excluded_by_partial_request?(path)
274
290
 
275
291
  # Precedence: Evaluate IgnoreOnFirstLoadProp only after partial keys have been checked
276
292
  return false if prop.is_a?(IgnoreOnFirstLoadProp) && !rendering_partial_component?
@@ -278,6 +294,29 @@ module InertiaRails
278
294
  true
279
295
  end
280
296
 
297
+ def excluded_by_once_cache?(prop, path)
298
+ return false unless prop.try(:once?)
299
+ return false if prop.try(:fresh?)
300
+ return false if explicitly_requested?(path)
301
+
302
+ once_key = (prop.once_key || path.join('.')).to_s
303
+ except_once_keys.include?(once_key)
304
+ end
305
+
306
+ def explicitly_requested?(path)
307
+ return false unless rendering_partial_component? && partial_keys.present?
308
+
309
+ path_with_prefixes = path_prefixes(path)
310
+ (path_with_prefixes & partial_keys).any?
311
+ end
312
+
313
+ def excluded_by_partial_request?(path)
314
+ return false unless rendering_partial_component? && (partial_keys.present? || partial_except_keys.present?)
315
+
316
+ path_with_prefixes = path_prefixes(path)
317
+ excluded_by_only_partial_keys?(path_with_prefixes) || excluded_by_except_partial_keys?(path_with_prefixes)
318
+ end
319
+
281
320
  def path_prefixes(parts)
282
321
  (0...parts.length).map do |i|
283
322
  parts[0..i].join('.')
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module InertiaRails
4
- VERSION = '3.13.0'
4
+ VERSION = '3.15.0'
5
5
  end
data/lib/inertia_rails.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'inertia_rails/version'
3
4
  require 'inertia_rails/renderer'
4
5
  require 'inertia_rails/engine'
5
6
 
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.13.0
4
+ version: 3.15.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-11-19 00:00:00.000000000 Z
12
+ date: 2025-12-12 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: railties
@@ -47,6 +47,7 @@ files:
47
47
  - lib/generators/inertia/install/install_generator.rb
48
48
  - lib/generators/inertia/install/js_package_manager.rb
49
49
  - lib/generators/inertia/install/templates/assets/inertia.svg
50
+ - lib/generators/inertia/install/templates/assets/rails.svg
50
51
  - lib/generators/inertia/install/templates/assets/react.svg
51
52
  - lib/generators/inertia/install/templates/assets/svelte.svg
52
53
  - lib/generators/inertia/install/templates/assets/vite_ruby.svg
@@ -199,8 +200,10 @@ files:
199
200
  - lib/inertia_rails/meta_tag.rb
200
201
  - lib/inertia_rails/meta_tag_builder.rb
201
202
  - lib/inertia_rails/middleware.rb
203
+ - lib/inertia_rails/once_prop.rb
202
204
  - lib/inertia_rails/optional_prop.rb
203
205
  - lib/inertia_rails/prop_mergeable.rb
206
+ - lib/inertia_rails/prop_onceable.rb
204
207
  - lib/inertia_rails/renderer.rb
205
208
  - lib/inertia_rails/rspec.rb
206
209
  - lib/inertia_rails/scroll_metadata.rb