render_turbo_stream 1.4.4 → 1.4.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +41 -7
- data/app/views/render_turbo_stream.html.erb +8 -2
- data/lib/render_turbo_stream/test/request_helpers.rb +52 -23
- data/lib/render_turbo_stream/test/rspec_request_helpers.rb +15 -7
- data/lib/render_turbo_stream/version.rb +1 -1
- data/lib/render_turbo_stream.rb +51 -11
- metadata +4 -4
- data/app/views/_render_turbo_stream.turbo_stream.erb +0 -49
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 187ae01e898e93a7b6a09936abc83f15e96172f4a76759844ff54c585d0a58bb
|
4
|
+
data.tar.gz: 8b361d4745339fb6bd83dd05ad784be75e82bf47f596e635e8bf8c567afeeff7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7d2fab8e12360c1756d53fc5dcd82479fd34a0fed8a6398f745449460325a28b173b22bdb805e0319815b2fa3745f52c15a7e0a09e9faeebedbcf5cdbaaa2bf7
|
7
|
+
data.tar.gz: 2f767606657e5f98281834676fb1a159aa8f799907dd43ec7dce770c6d2a2f7cdbc08f4e0d983964c231b5fbb466efee0659875a25cb25e8fc3c37fd75cb10d0
|
data/README.md
CHANGED
@@ -8,6 +8,8 @@ And build it dynamically: Most [turbo_power](https://github.com/marcoroth/turbo_
|
|
8
8
|
|
9
9
|
ATTENTION: This plugin is in a early state.
|
10
10
|
|
11
|
+
Hope this gem can help you.
|
12
|
+
|
11
13
|
An overview of how we design a rails-7 application with turbo
|
12
14
|
is [published on dev.to](https://dev.to/chmich/rails-7-vite-wrapping-up-1pia).
|
13
15
|
|
@@ -101,7 +103,7 @@ render_turbo_stream(
|
|
101
103
|
)
|
102
104
|
```
|
103
105
|
|
104
|
-
The `stream_partial` method is
|
106
|
+
The `stream_partial` method is just for rendering a partial alone.
|
105
107
|
|
106
108
|
```ruby
|
107
109
|
stream_partial(
|
@@ -129,9 +131,6 @@ render_turbo_stream(
|
|
129
131
|
:add_css_class,
|
130
132
|
'#colored-element',
|
131
133
|
'red'
|
132
|
-
],
|
133
|
-
[
|
134
|
-
|
135
134
|
]
|
136
135
|
]
|
137
136
|
)
|
@@ -141,14 +140,34 @@ Under the hood, inside a `*.turbo_stream.erb` template, it does the following: `
|
|
141
140
|
|
142
141
|
**WORKAROUND for redirects inside frame**
|
143
142
|
|
144
|
-
|
143
|
+
Suppose you have a CRUD controller that should do all its actions inside a turbo frame. Classic redirect_to, along with a Flash message, would raise "Render and/or redirect were called multiple times in this action". See [issue] (https://gitlab.com/sedl/renderturbostream/-/issues/3).
|
144
|
+
|
145
|
+
You can handle this by reloading the parent frame's src attribute. The code might look like this:
|
146
|
+
|
147
|
+
```ruby
|
148
|
+
def update
|
149
|
+
@car = Car.find(params['id'])
|
150
|
+
turbo_stream_save(
|
151
|
+
@car.update(car_params),
|
152
|
+
streams_on_success: [
|
153
|
+
[
|
154
|
+
:turbo_frame_set_src,
|
155
|
+
'cars-box',
|
156
|
+
cars_path
|
157
|
+
]
|
158
|
+
]
|
159
|
+
)
|
160
|
+
end
|
161
|
+
|
162
|
+
```
|
145
163
|
|
146
164
|
**Parameters for turbo_stream_save**
|
147
165
|
|
148
166
|
save_action,
|
149
|
-
redirect_on_success_to: nil,
|
167
|
+
redirect_on_success_to: nil, # does a regular redirect. Works if you are inside a turbo_frame and just want to redirect inside that frame BUT CANNOT STREAM OTHERS ACTIONS ON THE SAME RESPONSE https://github.com/rails/rails/issues/48056
|
168
|
+
turbo_redirect_on_success_to: nil, # does a full page redirect (break out of all frames by turbo_power redirect)
|
150
169
|
object: nil, # object used in save_action, example: @customer
|
151
|
-
id:
|
170
|
+
id: nil, # if nil: no partial is rendered
|
152
171
|
partial: nil, # example: 'customers/form' default: "#{controller_path}/#{id}"
|
153
172
|
action: 'replace', # options: append, prepend
|
154
173
|
locals: {}, # locals used by the partial
|
@@ -255,6 +274,17 @@ For more detailed testing of partials, there are view tests.
|
|
255
274
|
Testing the plugin itself: There is a [quick-and-dirty app](https://gitlab.com/sedl/renderturbostream_railsapp) which
|
256
275
|
includes the plugin and has tests done by rspec/request and capybara.
|
257
276
|
|
277
|
+
## More Configs
|
278
|
+
|
279
|
+
On test helpers, the marker for a turbo-stream target is in most cases the id of the target element. This is true for the standard turbo-stream functions. On `turbo_power` it is the same in most cases. `RenderTurboStream::Libs.first_attr_is_html_id()` checks for which methods this is true. You can override this:
|
280
|
+
|
281
|
+
```ruby
|
282
|
+
config.x.render_turbo_stream.first_attribute_is_html_id = %[replace append prepend turbo_frame_set_src]
|
283
|
+
```
|
284
|
+
|
285
|
+
This setting is relevant for testing helpers.
|
286
|
+
|
287
|
+
|
258
288
|
## Contributing
|
259
289
|
|
260
290
|
Contribution welcome.
|
@@ -262,3 +292,7 @@ Contribution welcome.
|
|
262
292
|
## License
|
263
293
|
|
264
294
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
295
|
+
|
296
|
+
## Thanks
|
297
|
+
|
298
|
+
Thanks to Marco Roth for turbo_power and thanks to DHH and the rails team for taking a bold new step by creating turbo.
|
@@ -1,13 +1,19 @@
|
|
1
1
|
<% rendered_partials = [] %>
|
2
2
|
|
3
|
+
|
3
4
|
<% streams.each do |s| %>
|
4
5
|
|
5
6
|
<% if s.is_a?(Array) %>
|
6
|
-
<%
|
7
|
+
<% attr_id = RenderTurboStream::Libs.first_attr_is_html_id(s.first) %>
|
8
|
+
<% h = { attributes: s, type: 'command' } %>
|
9
|
+
<% h[:target] = "##{s.second}" if attr_id %>
|
10
|
+
<% rendered_partials.push(h) %>
|
7
11
|
<% else %>
|
8
12
|
<% html = (render s[:partial], locals: s[:locals]&.symbolize_keys, formats: [:html]) %>
|
9
13
|
<% s.delete(:partial) %>
|
10
|
-
<%
|
14
|
+
<% s[:target] = "##{s[:id]}" %>
|
15
|
+
<% s.delete(:id) %>
|
16
|
+
<% rendered_partials.push({ html_response: html, type: 'partial' }.merge(s)) %>
|
11
17
|
<% end %>
|
12
18
|
|
13
19
|
|
@@ -4,24 +4,7 @@ module RenderTurboStream
|
|
4
4
|
|
5
5
|
# log as helper for the developer to see which flash is set and which partials are rendered to wich ids
|
6
6
|
def streams_log
|
7
|
-
|
8
|
-
r = []
|
9
|
-
if response.status == 302
|
10
|
-
r.push("redirect to #{turbo_redirect_to}")
|
11
|
-
else
|
12
|
-
all_responses.map do |a|
|
13
|
-
str = [
|
14
|
-
a['action'],
|
15
|
-
'id',
|
16
|
-
"«#{a['id']}»",
|
17
|
-
'by partial',
|
18
|
-
"«#{a['partial']}»",
|
19
|
-
(a['locals'].present? ? "locals: «#{a['locals']}»" : nil)
|
20
|
-
].compact.join(' ')
|
21
|
-
r.push(str)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
r
|
7
|
+
RenderTurboStream::Libs.all_responses(response)
|
25
8
|
end
|
26
9
|
|
27
10
|
# Returns the path to which turbo_stream.redirect_to would be applied.
|
@@ -29,11 +12,13 @@ module RenderTurboStream
|
|
29
12
|
resps = RenderTurboStream::Libs.all_responses(response)
|
30
13
|
url = nil
|
31
14
|
resps.each do |r|
|
32
|
-
if r['
|
33
|
-
if
|
34
|
-
url
|
35
|
-
|
36
|
-
|
15
|
+
if r['type'] == 'command'
|
16
|
+
if r['attributes'].first == 'redirect_to'
|
17
|
+
if url
|
18
|
+
url = 'ERROR: REDIRECT CALLED MORE THAN ONCE'
|
19
|
+
else
|
20
|
+
url = r['attributes'].second
|
21
|
+
end
|
37
22
|
end
|
38
23
|
end
|
39
24
|
end
|
@@ -66,6 +51,50 @@ module RenderTurboStream
|
|
66
51
|
def stream_targets_count
|
67
52
|
stream_targets.length
|
68
53
|
end
|
54
|
+
|
55
|
+
# Returns false if a given action such as "replace" (for: turbo_stream.replace) is not performed exactly once on a given target id. Otherwise, it returns an array of attributes that were used to call the function.
|
56
|
+
# For stream actions, this only works if the given action has the HTML-ID as its first element.
|
57
|
+
def stream_action_once(action, id)
|
58
|
+
all_responses = RenderTurboStream::Libs.all_responses(response)
|
59
|
+
counts = {}
|
60
|
+
res = nil
|
61
|
+
all_responses.each do |r|
|
62
|
+
|
63
|
+
if r['type'] == 'command'
|
64
|
+
act = r['attributes'].first
|
65
|
+
is_id = RenderTurboStream::Libs.first_attr_is_html_id(act)
|
66
|
+
if action.to_s == act && is_id && r['attributes'].second == id.to_s
|
67
|
+
k = [act, r['attributes'].second].join('-')
|
68
|
+
counts[k] ||= 0
|
69
|
+
counts[k] += 1
|
70
|
+
if counts[k] == 1
|
71
|
+
res = r['attributes']
|
72
|
+
else
|
73
|
+
res = false
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
elsif r['type'] == 'partial'
|
78
|
+
|
79
|
+
act = r['action']
|
80
|
+
is_id = r['target'][0] == '#'
|
81
|
+
_id = r['target'][1..-1]
|
82
|
+
if action.to_s == act && is_id && _id == id.to_s
|
83
|
+
k = [act, _id].join('-')
|
84
|
+
counts[k] ||= 0
|
85
|
+
counts[k] += 1
|
86
|
+
if counts[k] == 1
|
87
|
+
res = [act, id, { locals: r['locals'] }]
|
88
|
+
else
|
89
|
+
res = false
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
95
|
+
res
|
96
|
+
end
|
97
|
+
|
69
98
|
end
|
70
99
|
end
|
71
100
|
end
|
@@ -2,22 +2,30 @@ module RenderTurboStream
|
|
2
2
|
module Test
|
3
3
|
module RspecRequestHelpers
|
4
4
|
|
5
|
-
|
6
5
|
# expect status 200 and a each one time response to given ids
|
7
6
|
|
8
7
|
def expect_successful_saved(*ids)
|
9
8
|
responses = RenderTurboStream::Libs.all_responses(response)
|
10
|
-
|
9
|
+
id_counts = {}
|
11
10
|
responses.each do |r|
|
12
|
-
|
13
|
-
|
11
|
+
if r['target'].is_a?(Array)
|
12
|
+
r['target'].each do |t|
|
13
|
+
id = (t[0] == '#' ? t[1..-1] : t)
|
14
|
+
id_counts[t.to_s] ||= 0
|
15
|
+
id_counts[t.to_s] += 1
|
16
|
+
end
|
17
|
+
else
|
18
|
+
id = (r['target'][0] == '#' ? r['target'][1..-1] : r['target'])
|
19
|
+
id_counts[id] ||= 0
|
20
|
+
id_counts[id] += 1
|
21
|
+
end
|
14
22
|
end
|
15
23
|
|
16
24
|
expect(response.status).to eq(200)
|
17
|
-
expect(
|
25
|
+
expect(id_counts.keys.length).to eq(ids.length)
|
18
26
|
ids.each do |id|
|
19
|
-
expect(
|
20
|
-
expect(
|
27
|
+
expect(id_counts.key?(id)).to be_truthy
|
28
|
+
expect(id_counts[id]).to eq(1)
|
21
29
|
end
|
22
30
|
end
|
23
31
|
|
data/lib/render_turbo_stream.rb
CHANGED
@@ -8,7 +8,7 @@ module RenderTurboStream
|
|
8
8
|
|
9
9
|
def turbo_stream_save(
|
10
10
|
save_action,
|
11
|
-
redirect_on_success_to: nil, # does a regular redirect. Works if you are inside a turbo_frame and just want to redirect inside that frame BUT CANNOT STREAM OTHERS ACTIONS
|
11
|
+
redirect_on_success_to: nil, # does a regular redirect. Works if you are inside a turbo_frame and just want to redirect inside that frame BUT CANNOT STREAM OTHERS ACTIONS ON THE SAME RESPONSE https://github.com/rails/rails/issues/48056
|
12
12
|
turbo_redirect_on_success_to: nil, # does a full page redirect (break out of all frames by turbo_power redirect)
|
13
13
|
object: nil, # object used in save_action, example: @customer
|
14
14
|
id: nil, # if nil: no partial is rendered
|
@@ -43,7 +43,7 @@ module RenderTurboStream
|
|
43
43
|
|
44
44
|
#== Streams / Partials
|
45
45
|
|
46
|
-
streams =
|
46
|
+
streams = (id ? [id: id, partial: partial, locals: locals, action: action] : [])
|
47
47
|
|
48
48
|
if save_action
|
49
49
|
response.status = 200
|
@@ -160,7 +160,7 @@ module RenderTurboStream
|
|
160
160
|
ary = []
|
161
161
|
array.each do |pr|
|
162
162
|
if !pr.present?
|
163
|
-
a=1
|
163
|
+
a = 1
|
164
164
|
elsif pr.is_a?(Hash)
|
165
165
|
props = pr.symbolize_keys
|
166
166
|
part = (props[:partial].present? ? props[:partial] : props[:id]).gsub('-', '_')
|
@@ -214,7 +214,7 @@ module RenderTurboStream
|
|
214
214
|
|
215
215
|
all.select do |a|
|
216
216
|
if id.present?
|
217
|
-
a['
|
217
|
+
a['target'] == "##{id}"
|
218
218
|
else
|
219
219
|
false
|
220
220
|
end
|
@@ -223,15 +223,19 @@ module RenderTurboStream
|
|
223
223
|
end
|
224
224
|
|
225
225
|
def self.stream_targets(response)
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
226
|
+
responses = all_responses(response)
|
227
|
+
targets = []
|
228
|
+
responses.each do |r|
|
229
|
+
if r['target'].is_a?(Array)
|
230
|
+
r['target'].each do |t|
|
231
|
+
targets.push(t) unless targets.include?(t)
|
232
|
+
end
|
233
|
+
else
|
234
|
+
targets.push(r['target']) unless targets.include?(r['target'])
|
232
235
|
end
|
233
236
|
end
|
234
|
-
|
237
|
+
|
238
|
+
targets
|
235
239
|
end
|
236
240
|
|
237
241
|
def self.stream_target_response_count(response, id, total, &block)
|
@@ -252,5 +256,41 @@ module RenderTurboStream
|
|
252
256
|
|
253
257
|
end
|
254
258
|
|
259
|
+
# on most methods the first attribute is the target.
|
260
|
+
# This method checks for that
|
261
|
+
# it includes the methods from turbo-power
|
262
|
+
# used for test helpers
|
263
|
+
def self.first_attr_is_html_id(method)
|
264
|
+
config = Rails.configuration.x.render_turbo_stream.first_attribute_is_html_id
|
265
|
+
default = [
|
266
|
+
:graft,
|
267
|
+
:morph,
|
268
|
+
:inner_html,
|
269
|
+
:insert_adjacent_text,
|
270
|
+
:outer_html,
|
271
|
+
:text_content,
|
272
|
+
:add_css_class,
|
273
|
+
:remove_attribute,
|
274
|
+
:remove_css_class,
|
275
|
+
:set_attribute,
|
276
|
+
:set_dataset_attribute,
|
277
|
+
:set_property,
|
278
|
+
:set_style,
|
279
|
+
:set_styles,
|
280
|
+
:set_value,
|
281
|
+
:dispatch_event,
|
282
|
+
:reset_form,
|
283
|
+
:clear_storage,
|
284
|
+
:scroll_into_view,
|
285
|
+
:set_focus,
|
286
|
+
:turbo_frame_reload,
|
287
|
+
:turbo_frame_set_src,
|
288
|
+
:replace,
|
289
|
+
:append,
|
290
|
+
:prepend
|
291
|
+
]
|
292
|
+
(config.present? ? config : default).map{|m|m.to_sym}.include?(method.to_sym)
|
293
|
+
end
|
294
|
+
|
255
295
|
end
|
256
296
|
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: 1.4.
|
4
|
+
version: 1.4.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- christian
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-04-
|
11
|
+
date: 2023-04-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -38,7 +38,6 @@ files:
|
|
38
38
|
- README.md
|
39
39
|
- Rakefile
|
40
40
|
- app/controllers/render_turbo_stream/application_controller.rb
|
41
|
-
- app/views/_render_turbo_stream.turbo_stream.erb
|
42
41
|
- app/views/render_turbo_stream.html.erb
|
43
42
|
- app/views/render_turbo_stream.turbo_stream.erb
|
44
43
|
- lib/render_turbo_stream.rb
|
@@ -73,5 +72,6 @@ requirements: []
|
|
73
72
|
rubygems_version: 3.4.12
|
74
73
|
signing_key:
|
75
74
|
specification_version: 4
|
76
|
-
summary: Render partials
|
75
|
+
summary: Render partials and run javascripts directly from the controller. With test
|
76
|
+
helpers.
|
77
77
|
test_files: []
|
@@ -1,49 +0,0 @@
|
|
1
|
-
<% error = false %>
|
2
|
-
<% control = [] %>
|
3
|
-
<% streams = local_assigns[:streams] %>
|
4
|
-
<% streams.each do |args| %>
|
5
|
-
|
6
|
-
|
7
|
-
<% if args.is_a?(Array) %>
|
8
|
-
|
9
|
-
<% ctl = "turbo_stream.#{args.first}, #{args[1..-1].join(', ')}" %>
|
10
|
-
|
11
|
-
<% if args.last.is_a?(Proc) %>
|
12
|
-
<% Rails.logger.error(" RENDER TURBO STREAM BLOCK => #{ctl}") %>
|
13
|
-
<%#= turbo_stream.replace 'form' do %>
|
14
|
-
<%#= render partial: 'articles/form' %>
|
15
|
-
<%# end %>
|
16
|
-
<%= turbo_stream.send args.first, *(args[1..-2]) { args.last.call } %>
|
17
|
-
<% else %>
|
18
|
-
<% Rails.logger.error(" RENDER TURBO POWER => #{ctl}") %>
|
19
|
-
<%= turbo_stream.send args.first, *(args[1..-1]) %>
|
20
|
-
<% end %>
|
21
|
-
|
22
|
-
<% else %>
|
23
|
-
<% ctl = { partial: args[:partial], id: args[:id], action: args[:action] } %>
|
24
|
-
<% info = { id: args[:id], partial: args[:partial], locals: args[:locals] } %>
|
25
|
-
<% if !args[:action].present? %>
|
26
|
-
<% Rails.logger.error(" ERROR RENDER TURBO STREAM => MISSING ACTION => #{args}") %>
|
27
|
-
<% error = true %>
|
28
|
-
|
29
|
-
<% elsif args[:action].present? %>
|
30
|
-
<% Rails.logger.debug(" • render-turbo-stream #{args[:action].upcase} => #{info}") %>
|
31
|
-
<%= turbo_stream.send args[:action].to_sym, args[:id] do %>
|
32
|
-
<%= render args[:partial], locals: args[:locals]&.symbolize_keys %>
|
33
|
-
<% end %>
|
34
|
-
|
35
|
-
<% else %>
|
36
|
-
<% Rails.logger.error(" ERROR RENDER TURBO STREAM => NOTHING DONE! => #{args}") %>
|
37
|
-
<% end %>
|
38
|
-
<% end %>
|
39
|
-
|
40
|
-
<% control.push(ctl) %>
|
41
|
-
|
42
|
-
<% end %>
|
43
|
-
|
44
|
-
<% if error %>
|
45
|
-
<% Rails.logger.error(" RENDER TURBO STREAM HAD ERRORS, REPEATING WHOLE ARRAY: ") %>
|
46
|
-
<% control.each do |c| %>
|
47
|
-
<% Rails.logger.error(" #{c}") %>
|
48
|
-
<% end %>
|
49
|
-
<% end %>
|