render_turbo_stream 4.1.6 → 4.2.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/README.md +28 -0
- data/app/controllers/render_turbo_stream/render_controller.rb +4 -0
- data/app/views/render_turbo_stream.turbo_stream.erb +14 -8
- data/app/views/render_turbo_stream_request_test.html.erb +11 -6
- data/lib/render_turbo_stream/channel_libs.rb +29 -23
- data/lib/render_turbo_stream/check_template.rb +2 -13
- data/lib/render_turbo_stream/controller_channel_helpers.rb +4 -4
- data/lib/render_turbo_stream/controller_helpers.rb +3 -3
- data/lib/render_turbo_stream/controller_libs.rb +25 -18
- data/lib/render_turbo_stream/libs.rb +13 -0
- data/lib/render_turbo_stream/version.rb +1 -1
- metadata +8 -8
- data/app/controllers/render_turbo_stream/render_turbo_stream_render_controller.rb +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e0baf30f6152a1308687add8e14fda8ae815bfa43e54f9b4ffc6d859accc5e5b
|
4
|
+
data.tar.gz: a61f84ab272df1447b3a4cd38ef5dcbf3702390e360cbb03d5f172f0056aa760
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5f6b26a244628091a4385883b04d588d682f1da0144dd56a827e74cceb5d61df5bdeeb8eb72e041c9203995b25f1b62605fde0d5d4eadc611b3ef7a02dd8df54
|
7
|
+
data.tar.gz: bf8a7eaae4377b4a52f4200057f9dd4e8e8273fdee243f258cf1e65a63f935873d11a9686e73e1e353b54c5a05458781a6811c991f76650d1810da6dfa2b5e0a
|
data/README.md
CHANGED
@@ -170,6 +170,34 @@ If this config is set to true, Turbo::StreamsChannel is installed and a current
|
|
170
170
|
|
171
171
|
If an `if_success_redirect_to` argument is provided and the save action was successful, `turbo_stream_save` would send the partials by channel.
|
172
172
|
|
173
|
+
**target-ID: Avoid the same definition in multiple places**
|
174
|
+
|
175
|
+
Without this gem a turbo action would be wrapped within two frames, for example:
|
176
|
+
|
177
|
+
```haml
|
178
|
+
= turbo_stream.replace 'target-id' do
|
179
|
+
= render 'a partial'
|
180
|
+
|
181
|
+
```
|
182
|
+
|
183
|
+
and within a partial:
|
184
|
+
|
185
|
+
```haml
|
186
|
+
= turbo_frame_tag 'target-id' do
|
187
|
+
... content
|
188
|
+
```
|
189
|
+
|
190
|
+
The `turbo_frame_tag` would stay inside a partial in most cases. The reason is: On the first load, the target-id must be delivered up front, so that if the tag needs to be replaced later, turbo knows which part to replace.
|
191
|
+
|
192
|
+
This means that the target id must be defined in several places: inside a partial and at the place where the turbo action is defined.
|
193
|
+
|
194
|
+
In order to avoid this kind of tedious coding, the gem has a kind of fallback built in: If the argument `partial` is given, but the attribute `target_id` is not, the gem will get the target_id from the partial. The process is:
|
195
|
+
|
196
|
+
1. Render the partial with the provided locals
|
197
|
+
2. Grabs into the partial by Nokogiri and looks for a turbo_frame_tag and fetches the target_id.
|
198
|
+
3. If all that not is found it raises a exception
|
199
|
+
4. wraps the partial within the `turbo_stream.*` and sends this to the front.
|
200
|
+
|
173
201
|
# Request Testing
|
174
202
|
|
175
203
|
To test if the whole system works together, including javascript actions, so that finally a part reaches the surface, there is **Capybara** system testing. But it is a good practice to **break tests into smaller pieces**. So, there are helpers for **enabling the much faster request tests that are much easier to maintain**.
|
@@ -14,22 +14,28 @@
|
|
14
14
|
<% else %>
|
15
15
|
<% ctl = { partial: args[:partial], target_id: args[:target_id], action: args[:action] } %>
|
16
16
|
|
17
|
+
|
18
|
+
|
19
|
+
<% rendered_html = render(partial: args[:partial], locals: args[:locals]&.symbolize_keys, formats: [:html]) %>
|
20
|
+
<% unless args[:target].present? %>
|
21
|
+
<% args[:target] = RenderTurboStream::Libs.fetch_arguments_from_rendered_string(rendered_html)[:target] %>
|
22
|
+
<% unless args[:target].present? %>
|
23
|
+
<% raise 'No target specified by arguments and no target found inside the rendered partial' %>
|
24
|
+
<% end %>
|
25
|
+
<% end %>
|
26
|
+
|
27
|
+
|
17
28
|
<% target_id = RenderTurboStream::Libs.target_to_target_id(args[:target]) %>
|
18
29
|
|
19
30
|
<% info = { target_id: args[:target_id], partial: args[:partial], locals: args[:locals] } %>
|
20
31
|
|
21
32
|
|
22
|
-
|
23
33
|
<% if args[:action].present? %>
|
24
34
|
<% Rails.logger.debug(" • render-turbo-stream #{args[:action].upcase} => #{info}") %>
|
25
35
|
<%= turbo_stream.send args[:action].to_sym, target_id do %>
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
<% end %>
|
30
|
-
<% else %>
|
31
|
-
<%= render args[:partial], locals: args[:locals]&.symbolize_keys %>
|
32
|
-
<% end %>
|
36
|
+
|
37
|
+
<%= rendered_html %>
|
38
|
+
|
33
39
|
<% end %>
|
34
40
|
|
35
41
|
<% else %>
|
@@ -10,15 +10,20 @@
|
|
10
10
|
<% rendered_partials.push(h) %>
|
11
11
|
<% else %>
|
12
12
|
|
13
|
-
<% wrap = RenderTurboStream::CheckTemplate.new(partial: s[:partial], action: s[:action]).add_turbo_frame_tag? %>
|
14
13
|
|
15
|
-
<% if wrap %>
|
16
|
-
<% html = turbo_frame_tag RenderTurboStream::Libs.target_to_target_id(s[:target]) do %>
|
17
|
-
<%= (render s[:partial], locals: s[:locals]&.symbolize_keys, formats: [:html]) %>
|
18
|
-
<% end %>
|
19
|
-
<% else %>
|
20
14
|
<% html = (render s[:partial], locals: s[:locals]&.symbolize_keys, formats: [:html]) %>
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
<% unless s[:target].present? %>
|
19
|
+
<% s[:target] = RenderTurboStream::Libs.fetch_arguments_from_rendered_string(html)[:target] %>
|
20
|
+
<% unless s[:target].present? %>
|
21
|
+
<% raise 'No target specified by arguments and no target found inside the rendered partial' %>
|
22
|
+
<% end %>
|
21
23
|
<% end %>
|
24
|
+
|
25
|
+
|
26
|
+
|
22
27
|
<% s[:target] = s[:target] %>
|
23
28
|
<% s.delete(:id) %>
|
24
29
|
<% rendered_partials.push({ html_response: html, type: 'stream-partial' }.merge(s)) %>
|
@@ -7,9 +7,10 @@ module RenderTurboStream
|
|
7
7
|
|
8
8
|
def render_to_channel(channel, target, action, controller_self, partial: nil, template: nil, locals: nil)
|
9
9
|
|
10
|
+
_locals = (locals ? locals : {})
|
11
|
+
|
10
12
|
# instance variables
|
11
13
|
|
12
|
-
target_id = RenderTurboStream::Libs.target_to_target_id(target)
|
13
14
|
check_template = RenderTurboStream::CheckTemplate.new(
|
14
15
|
partial: partial,
|
15
16
|
template: template,
|
@@ -19,35 +20,40 @@ module RenderTurboStream
|
|
19
20
|
|
20
21
|
# add instance_variables to locals
|
21
22
|
|
22
|
-
locals = {} unless locals # prevent error missing keys for nil
|
23
|
-
if check_template.add_turbo_frame_tag?
|
24
|
-
_layout = 'layouts/add_turbo_frame_tag'
|
25
|
-
_locals = locals.merge(
|
26
|
-
{
|
27
|
-
render_turbo_stream_partial: partial,
|
28
|
-
render_turbo_stream_target_id: target_id
|
29
|
-
}
|
30
|
-
)
|
31
|
-
else
|
32
|
-
_locals = locals
|
33
|
-
_layout = false
|
34
|
-
end
|
35
23
|
check_template.templates_instance_variables.each do |v|
|
36
24
|
_locals[:"render_turbo_stream_instance_variable_#{v}"] = controller_self.instance_variable_get(v.to_s)
|
37
25
|
end
|
38
26
|
|
27
|
+
# fetch target-id
|
28
|
+
|
29
|
+
target_id = RenderTurboStream::Libs.target_to_target_id(target)
|
30
|
+
if !target.present? || Rails.env.test?
|
31
|
+
if partial.present?
|
32
|
+
rendered_html = RenderController.render(partial: partial, locals: _locals, layout: false)
|
33
|
+
elsif template.present?
|
34
|
+
rendered_html = RenderController.render(template: template, locals: _locals, layout: false)
|
35
|
+
end
|
36
|
+
if !target.present?
|
37
|
+
r = RenderTurboStream::Libs.fetch_arguments_from_rendered_string(rendered_html)
|
38
|
+
target_id = r[:target_id]
|
39
|
+
target = r[:target]
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
unless target.present? && target_id.present?
|
44
|
+
raise 'No target specified by arguments and no target found inside the rendered partial'
|
45
|
+
end
|
46
|
+
|
39
47
|
# add headers for test
|
40
48
|
|
41
49
|
if Rails.env.test?
|
42
|
-
html = RenderTurboStreamRenderController.render(partial: partial, locals: _locals, layout: _layout) if partial
|
43
|
-
html = RenderTurboStreamRenderController.render(template: template, locals: _locals, layout: _layout) if template
|
44
50
|
props = {
|
45
51
|
target: target,
|
46
52
|
action: action,
|
47
53
|
type: 'channel-partial',
|
48
54
|
locals: locals,
|
49
55
|
channel: channel,
|
50
|
-
html_response:
|
56
|
+
html_response: rendered_html.to_s
|
51
57
|
}
|
52
58
|
|
53
59
|
props[:partial] = partial if partial
|
@@ -66,23 +72,23 @@ module RenderTurboStream
|
|
66
72
|
|
67
73
|
# send
|
68
74
|
|
69
|
-
if partial
|
75
|
+
if partial.present?
|
70
76
|
Turbo::StreamsChannel.send(
|
71
77
|
"broadcast_#{action}_to",
|
72
78
|
channel.to_s,
|
73
79
|
target: target_id,
|
74
80
|
partial: partial,
|
75
81
|
locals: _locals&.symbolize_keys,
|
76
|
-
layout:
|
82
|
+
layout: false
|
77
83
|
)
|
78
|
-
elsif template
|
84
|
+
elsif template.present?
|
79
85
|
Turbo::StreamsChannel.send(
|
80
86
|
"broadcast_#{action}_to",
|
81
87
|
channel.to_s,
|
82
88
|
target: target_id,
|
83
89
|
template: template,
|
84
|
-
locals:
|
85
|
-
layout:
|
90
|
+
locals: _locals&.symbolize_keys,
|
91
|
+
layout: false
|
86
92
|
)
|
87
93
|
end
|
88
94
|
end
|
@@ -114,7 +120,7 @@ module RenderTurboStream
|
|
114
120
|
end
|
115
121
|
end
|
116
122
|
|
117
|
-
content =
|
123
|
+
content = RenderController.render(template: 'render_turbo_stream_command', layout: false, locals: { command: command, arguments: arguments })
|
118
124
|
|
119
125
|
Turbo::StreamsChannel.broadcast_stream_to(
|
120
126
|
channel,
|
@@ -23,12 +23,12 @@ module RenderTurboStream
|
|
23
23
|
if $render_turbo_stream_check_templates[@key]
|
24
24
|
@result = $render_turbo_stream_check_templates[@key]
|
25
25
|
else
|
26
|
-
@result = { instance_variables: []
|
26
|
+
@result = { instance_variables: [] }
|
27
27
|
fetch_nested_partials(1, partial: @partial_path, template: @template_path)
|
28
28
|
$render_turbo_stream_check_templates[@key] ||= @result
|
29
29
|
end
|
30
30
|
else
|
31
|
-
@result = { instance_variables: []
|
31
|
+
@result = { instance_variables: [] }
|
32
32
|
fetch_nested_partials(1, partial: @partial_path, template: @template_path)
|
33
33
|
end
|
34
34
|
end
|
@@ -37,10 +37,6 @@ module RenderTurboStream
|
|
37
37
|
@result[:instance_variables]
|
38
38
|
end
|
39
39
|
|
40
|
-
def add_turbo_frame_tag?
|
41
|
-
@result[:add_turbo_frame_tag]
|
42
|
-
end
|
43
|
-
|
44
40
|
private
|
45
41
|
|
46
42
|
def production?
|
@@ -67,13 +63,6 @@ module RenderTurboStream
|
|
67
63
|
end
|
68
64
|
end
|
69
65
|
|
70
|
-
conf = Rails.configuration.x.render_turbo_stream.auto_wrap_for_actions
|
71
|
-
if stack_level == 1 && conf.present? && conf.include?(@action.to_sym)
|
72
|
-
unless _code.match(/(turbo_frame_tag|turbo-frame)/)
|
73
|
-
@result[:add_turbo_frame_tag] = true
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
66
|
loop do
|
78
67
|
_matched_partial = _code.match((/\brender[ ](partial:|())(|[ ])("|')[a-z_\/]+("|')/))
|
79
68
|
_code = _code[(_code.index(_matched_partial.to_s) + 5)..-1]
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module RenderTurboStream
|
2
2
|
module ControllerChannelHelpers
|
3
3
|
|
4
|
-
def render_to_all(target_id, action = :replace, partial: nil, template: nil, locals: nil)
|
4
|
+
def render_to_all(target_id = nil, action = :replace, partial: nil, template: nil, locals: nil)
|
5
5
|
evaluate_instance_variables
|
6
6
|
render_to_channel(
|
7
7
|
'all',
|
@@ -13,7 +13,7 @@ module RenderTurboStream
|
|
13
13
|
)
|
14
14
|
end
|
15
15
|
|
16
|
-
def render_to_me(target_id, action = :replace, partial: nil, locals: nil)
|
16
|
+
def render_to_me(target_id = nil, action = :replace, partial: nil, locals: nil)
|
17
17
|
begin
|
18
18
|
u_id = helpers.current_user&.id
|
19
19
|
unless u_id.present?
|
@@ -34,7 +34,7 @@ module RenderTurboStream
|
|
34
34
|
)
|
35
35
|
end
|
36
36
|
|
37
|
-
def render_to_authenticated_group(group, target_id, action = :replace, partial: nil, locals: nil)
|
37
|
+
def render_to_authenticated_group(group, target_id = nil, action = :replace, partial: nil, locals: nil)
|
38
38
|
begin
|
39
39
|
u_id = helpers.current_user&.id
|
40
40
|
unless u_id.present?
|
@@ -55,7 +55,7 @@ module RenderTurboStream
|
|
55
55
|
)
|
56
56
|
end
|
57
57
|
|
58
|
-
def render_to_channel(channel, target_id, action, partial: nil, template: nil, locals: nil, instance_variables: true)
|
58
|
+
def render_to_channel(channel, target_id = nil, action = :replace, partial: nil, template: nil, locals: nil, instance_variables: true)
|
59
59
|
|
60
60
|
raise 'Arguments partial and template cannot both be specified' if partial && template
|
61
61
|
|
@@ -21,7 +21,7 @@ module RenderTurboStream
|
|
21
21
|
if_error_add: nil, # additional partials that should be rendered if save_action failed
|
22
22
|
add: [], # additional streams
|
23
23
|
|
24
|
-
if_success_notices: nil, # array of strings, override default generated flash generation in the case of success
|
24
|
+
if_success_notices: nil, # array of strings, or string, override default generated flash generation in the case of success
|
25
25
|
if_error_alerts: nil,
|
26
26
|
add_notices: nil, # array of strings
|
27
27
|
add_alerts: nil,
|
@@ -132,11 +132,11 @@ module RenderTurboStream
|
|
132
132
|
else
|
133
133
|
r[:target] = props[:target]
|
134
134
|
end
|
135
|
-
raise "Missing attribute :target in #{props}" if !props[:target].present?
|
136
135
|
r.delete(:target_id)
|
137
136
|
r[:action] = (props[:action].present? ? props[:action] : :replace)
|
138
137
|
r[:partial] = RenderTurboStream::Libs.partial_path(props[:target], props[:target_id], controller_path, props[:partial])
|
139
138
|
r[:type] = 'stream-partial'
|
139
|
+
|
140
140
|
ary.push(r)
|
141
141
|
elsif pr.is_a?(Array)
|
142
142
|
raise "array has to contain at least one element: #{pr}" unless pr.first.present?
|
@@ -157,7 +157,7 @@ module RenderTurboStream
|
|
157
157
|
|
158
158
|
# renders a partial to turbo_stream
|
159
159
|
|
160
|
-
def stream_partial(target_id, partial: nil, action: :replace, locals: {})
|
160
|
+
def stream_partial(target_id = nil, partial: nil, action: :replace, locals: {})
|
161
161
|
render_turbo_stream(
|
162
162
|
[
|
163
163
|
{
|
@@ -5,7 +5,7 @@ module RenderTurboStream
|
|
5
5
|
@save_action = save_action
|
6
6
|
end
|
7
7
|
|
8
|
-
def generate_flash(
|
8
|
+
def generate_flash(model_name, controller_action, if_success_notices, if_error_alerts, add_notices, add_alerts)
|
9
9
|
|
10
10
|
target_id = (Rails.configuration.x.render_turbo_stream.flash_target_id rescue nil)
|
11
11
|
raise "Missing configuration: config.x.render_turbo_stream.flash_target_id" unless target_id
|
@@ -14,26 +14,33 @@ module RenderTurboStream
|
|
14
14
|
turbo_action = Rails.configuration.x.render_turbo_stream.flash_turbo_action
|
15
15
|
raise "Missing configuration: configuration.x.render_turbo_stream.flash_turbo_action" unless turbo_action
|
16
16
|
|
17
|
-
|
18
17
|
if @save_action
|
19
18
|
notices = if if_success_notices
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
19
|
+
if if_success_notices.is_a?(String)
|
20
|
+
[if_success_notices]
|
21
|
+
else
|
22
|
+
if_success_notices
|
23
|
+
end
|
24
|
+
else
|
25
|
+
str = I18n.t(
|
26
|
+
"activerecord.render_turbo_stream_success.#{controller_action}"
|
27
|
+
)
|
28
|
+
[format(str, model_name: model_name)]
|
29
|
+
end
|
27
30
|
alerts = []
|
28
31
|
else
|
29
32
|
alerts = if if_error_alerts
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
33
|
+
if if_error_alerts.is_a?(String)
|
34
|
+
[if_error_alerts]
|
35
|
+
else
|
36
|
+
if_error_alerts
|
37
|
+
end
|
38
|
+
else
|
39
|
+
str = I18n.t(
|
40
|
+
"activerecord.render_turbo_stream_errors.#{controller_action}"
|
41
|
+
)
|
42
|
+
[format(str, model_name: model_name)]
|
43
|
+
end
|
37
44
|
notices = []
|
38
45
|
end
|
39
46
|
|
@@ -63,13 +70,13 @@ module RenderTurboStream
|
|
63
70
|
{ turbo_actions: turbo_actions, alerts: alerts, notices: notices }
|
64
71
|
end
|
65
72
|
|
66
|
-
def additional_actions(
|
73
|
+
def additional_actions(if_success_add, if_error_add, add)
|
67
74
|
|
68
75
|
(@save_action ? make_actions(if_success_add) : make_actions(if_error_add)) + make_actions(add)
|
69
76
|
|
70
77
|
end
|
71
78
|
|
72
|
-
def generate_action(
|
79
|
+
def generate_action(controller_path, target_id, action, partial, locals)
|
73
80
|
libs = RenderTurboStream::Libs
|
74
81
|
target = libs.target_id_to_target(target_id)
|
75
82
|
_partial = libs.partial_path(nil, target_id, controller_path, partial)
|
@@ -29,5 +29,18 @@ module RenderTurboStream
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
+
def self.fetch_arguments_from_rendered_string(rendered_string)
|
33
|
+
noko = Nokogiri::HTML(rendered_string)
|
34
|
+
frame = noko.at_css('turbo-frame')
|
35
|
+
if frame.present?
|
36
|
+
{
|
37
|
+
target_id: frame[:id],
|
38
|
+
target: target_id_to_target(frame[:id])
|
39
|
+
}
|
40
|
+
else
|
41
|
+
{}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
32
45
|
end
|
33
46
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: render_turbo_stream
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- christian
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-05-
|
11
|
+
date: 2023-05-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -27,10 +27,10 @@ dependencies:
|
|
27
27
|
description: 'A set of helpers that allow a UNIFIED WORKFLOW for TurboStream and TurboStreams::Channel.
|
28
28
|
To avoid a heavy mix of view and logic, partials and templates can be rendered directly
|
29
29
|
from the controller. There is no need to write *.turbo_stream.* templates anymore.
|
30
|
-
Logic can stay on
|
31
|
-
|
32
|
-
|
33
|
-
|
30
|
+
Logic can stay on in the controller. Javascript actions can also be executed directly
|
31
|
+
from the controller. TESTING: To reduce the amount of hard-to-maintain system tests,
|
32
|
+
this gem allows detailed request tests. A DEMO PROJECT with all this built in, along
|
33
|
+
with system and request tests, is linked in the README.'
|
34
34
|
email:
|
35
35
|
- christian@sedlmair.ch
|
36
36
|
executables: []
|
@@ -40,7 +40,7 @@ files:
|
|
40
40
|
- README.md
|
41
41
|
- Rakefile
|
42
42
|
- app/controllers/render_turbo_stream/application_controller.rb
|
43
|
-
- app/controllers/render_turbo_stream/
|
43
|
+
- app/controllers/render_turbo_stream/render_controller.rb
|
44
44
|
- app/views/layouts/_add_turbo_frame_tag.html.erb
|
45
45
|
- app/views/render_turbo_stream.turbo_stream.erb
|
46
46
|
- app/views/render_turbo_stream_command.html.erb
|
@@ -86,5 +86,5 @@ requirements: []
|
|
86
86
|
rubygems_version: 3.4.12
|
87
87
|
signing_key:
|
88
88
|
specification_version: 4
|
89
|
-
summary:
|
89
|
+
summary: Makes working with Turbo fun and ensures quality.
|
90
90
|
test_files: []
|