Skip to content

Commit e9b2b9f

Browse files
authored
Merge pull request #152 from skryukov/refactor-always-prop
Add support for `always` and `except`
2 parents e8c8be2 + 35ac7c8 commit e9b2b9f

19 files changed

+310
-92
lines changed

docs/guide/partial-reloads.md

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,6 @@ router.visit(url, {
4646

4747
## Except certain props
4848

49-
> [!WARNING]
50-
> The `except` option is not yet supported by the Inertia Rails.
51-
5249
:::tabs key:frameworks
5350
== Vue
5451

@@ -204,13 +201,7 @@ On the inverse, you can use the `InertiaRails.always` method to specify that a p
204201
class UsersController < ApplicationController
205202
def index
206203
render inertia: 'Users/Index', props: {
207-
users: InertiaRails.always(User.all),
208-
209-
# Also works with block:
210-
# users: InertiaRails.always { User.all },
211-
212-
# Also works with a lambda:
213-
# users: InertiaRails.always(-> { User.all }),
204+
users: InertiaRails.always { User.all },
214205
}
215206
end
216207
end
@@ -236,6 +227,11 @@ class UsersController < ApplicationController
236227
# OPTIONALLY included on partial reloads
237228
# ONLY evaluated when needed
238229
users: InertiaRails.lazy { User.all },
230+
231+
# ALWAYS included on standard visits
232+
# ALWAYS included on partial reloads
233+
# ALWAYS evaluated
234+
users: InertiaRails.always(User.all),
239235
}
240236
end
241237
end

lib/inertia_rails/always_prop.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
# frozen_string_literal: true
2+
3+
module InertiaRails
4+
class AlwaysProp < BaseProp
5+
end
6+
end

lib/inertia_rails/base_prop.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# frozen_string_literal: true
2+
3+
module InertiaRails
4+
# Base class for all props.
5+
class BaseProp
6+
def initialize(&block)
7+
@block = block
8+
end
9+
10+
def call(controller)
11+
controller.instance_exec(&@block)
12+
end
13+
end
14+
end

lib/inertia_rails/inertia_rails.rb

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,26 @@
1-
# Needed for `thread_mattr_accessor`
2-
require 'active_support/core_ext/module/attribute_accessors_per_thread'
3-
require 'inertia_rails/lazy'
1+
require 'inertia_rails/base_prop'
2+
require 'inertia_rails/always_prop'
3+
require 'inertia_rails/lazy_prop'
44
require 'inertia_rails/configuration'
55

66
module InertiaRails
7-
CONFIGURATION = Configuration.default
7+
class << self
8+
CONFIGURATION = Configuration.default
89

9-
def self.configure
10-
yield(CONFIGURATION)
11-
end
10+
def configure
11+
yield(CONFIGURATION)
12+
end
1213

13-
def self.configuration
14-
CONFIGURATION
15-
end
14+
def configuration
15+
CONFIGURATION
16+
end
17+
18+
def lazy(value = nil, &block)
19+
LazyProp.new(value, &block)
20+
end
1621

17-
def self.lazy(value = nil, &block)
18-
InertiaRails::Lazy.new(value, &block)
22+
def always(&block)
23+
AlwaysProp.new(&block)
24+
end
1925
end
2026
end

lib/inertia_rails/lazy.rb

Lines changed: 0 additions & 28 deletions
This file was deleted.

lib/inertia_rails/lazy_prop.rb

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# frozen_string_literal: true
2+
3+
module InertiaRails
4+
class LazyProp < BaseProp
5+
def initialize(value = nil, &block)
6+
raise ArgumentError, 'You must provide either a value or a block, not both' if value && block
7+
8+
@value = value
9+
@block = block
10+
end
11+
12+
def call(controller)
13+
value.respond_to?(:call) ? controller.instance_exec(&value) : value
14+
end
15+
16+
def value
17+
@value.nil? ? @block : @value
18+
end
19+
end
20+
end

lib/inertia_rails/renderer.rb

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
# frozen_string_literal: true
2+
13
require 'net/http'
24
require 'json'
35
require_relative "inertia_rails"
@@ -64,24 +66,34 @@ def shared_data
6466
# Functionally, this permits using either string or symbol keys in the controller. Since the results
6567
# is cast to json, we should treat string/symbol keys as identical.
6668
def merge_props(shared_data, props)
67-
shared_data.deep_symbolize_keys.send(@deep_merge ? :deep_merge : :merge, props.deep_symbolize_keys)
69+
if @deep_merge
70+
shared_data.deep_symbolize_keys.deep_merge!(props.deep_symbolize_keys)
71+
else
72+
shared_data.symbolize_keys.merge(props.symbolize_keys)
73+
end
6874
end
6975

7076
def computed_props
7177
_props = merge_props(shared_data, props).select do |key, prop|
7278
if rendering_partial_component?
73-
key.in? partial_keys
79+
partial_keys.none? || key.in?(partial_keys) || prop.is_a?(AlwaysProp)
7480
else
75-
!prop.is_a?(InertiaRails::Lazy)
81+
!prop.is_a?(LazyProp)
7682
end
7783
end
7884

79-
deep_transform_values(
80-
_props,
81-
lambda do |prop|
82-
prop.respond_to?(:call) ? controller.instance_exec(&prop) : prop
85+
drop_partial_except_keys(_props) if rendering_partial_component?
86+
87+
deep_transform_values _props do |prop|
88+
case prop
89+
when BaseProp
90+
prop.call(controller)
91+
when Proc
92+
controller.instance_exec(&prop)
93+
else
94+
prop
8395
end
84-
)
96+
end
8597
end
8698

8799
def page
@@ -93,18 +105,32 @@ def page
93105
}
94106
end
95107

96-
def deep_transform_values(hash, proc)
97-
return proc.call(hash) unless hash.is_a? Hash
108+
def deep_transform_values(hash, &block)
109+
return block.call(hash) unless hash.is_a? Hash
98110

99-
hash.transform_values {|value| deep_transform_values(value, proc)}
111+
hash.transform_values {|value| deep_transform_values(value, &block)}
112+
end
113+
114+
def drop_partial_except_keys(hash)
115+
partial_except_keys.each do |key|
116+
parts = key.to_s.split('.').map(&:to_sym)
117+
*initial_keys, last_key = parts
118+
current = initial_keys.any? ? hash.dig(*initial_keys) : hash
119+
120+
current.delete(last_key) if current.is_a?(Hash) && !current[last_key].is_a?(AlwaysProp)
121+
end
100122
end
101123

102124
def partial_keys
103125
(@request.headers['X-Inertia-Partial-Data'] || '').split(',').compact.map(&:to_sym)
104126
end
105127

128+
def partial_except_keys
129+
(@request.headers['X-Inertia-Partial-Except'] || '').split(',').filter_map(&:to_sym)
130+
end
131+
106132
def rendering_partial_component?
107-
@request.inertia_partial? && @request.headers['X-Inertia-Partial-Component'] == component
133+
@request.headers['X-Inertia-Partial-Component'] == component
108134
end
109135

110136
def resolve_component(component)

lib/patches/request.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ def inertia?
44
end
55

66
def inertia_partial?
7-
key? 'HTTP_X_INERTIA_PARTIAL_DATA'
7+
key?('HTTP_X_INERTIA_PARTIAL_COMPONENT')
88
end
99
end
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,5 @@
11
class ApplicationController < ActionController::Base
2+
def controller_method
3+
'controller_method value'
4+
end
25
end

spec/dummy/app/controllers/inertia_render_test_controller.rb

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,23 @@ def props
77
}
88
end
99

10+
def except_props
11+
render inertia: 'TestComponent', props: {
12+
flat: 'flat param',
13+
lazy: InertiaRails.lazy('lazy param'),
14+
nested_lazy: InertiaRails.lazy do
15+
{
16+
first: 'first nested lazy param',
17+
}
18+
end,
19+
nested: {
20+
first: 'first nested param',
21+
second: 'second nested param'
22+
},
23+
always: InertiaRails.always { 'always prop' }
24+
}
25+
end
26+
1027
def view_data
1128
render inertia: 'TestComponent', view_data: {
1229
name: 'Brian',
@@ -34,4 +51,15 @@ def lazy_props
3451
grit: InertiaRails.lazy(->{ 'intense' })
3552
}
3653
end
54+
55+
def always_props
56+
render inertia: 'TestComponent', props: {
57+
always: InertiaRails.always { 'always prop' },
58+
regular: 'regular prop',
59+
lazy: InertiaRails.lazy do
60+
'lazy prop'
61+
end,
62+
another_lazy: InertiaRails.lazy(->{ 'another lazy prop' })
63+
}
64+
end
3765
end

0 commit comments

Comments
 (0)