render_turbo_stream 1.2.2 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +34 -8
- data/app/views/render_turbo_stream.html.erb +16 -0
- data/app/views/render_turbo_stream.turbo_stream.erb +41 -0
- data/lib/render_turbo_stream/test/request_helpers.rb +12 -3
- data/lib/render_turbo_stream/version.rb +1 -1
- data/lib/render_turbo_stream.rb +25 -35
- metadata +10 -10
- data/app/views/render_turbo_stream_partials.html.erb +0 -12
- data/app/views/render_turbo_stream_partials.turbo_stream.erb +0 -52
- data/app/views/render_turbo_stream_redirect.turbo_stream.erb +0 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7737e1e5b1a6b397c22634b0a7efe6ee3f5d550a041fc667323c3b91dc5bf31b
|
4
|
+
data.tar.gz: a254e95ff504444aec88dfb25bfeb24c30f10447b2f47bfe7ff40ef57bb3ed0b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5d1c9a165d5471062752980dc3af0c9cd87908d16e37f000953aceb78c23f458ec5bd6585ec571068572479c7b088b9d6a442f5f993f05f03a8f46d6cc4cf518
|
7
|
+
data.tar.gz: 6db4979439d1399e40f1c786f8f4c78de5828aa4c310810bd4950928acb41cf8db6662ba238c7776337161d76d9139b180d8737bd042329854d8e4f3d366c690
|
data/README.md
CHANGED
@@ -4,6 +4,8 @@ Defining templates like `(create|update).turbo_stream.haml` annoyed me.
|
|
4
4
|
|
5
5
|
Working consistently with turbo_stream means shooting lots of partials from the backend to the frontend. This always requires the same attributes: the path to the partial, the html-id that turbo_stream points to, and maybe some locals. This gem serialises that: Partials can be controlled directly from the controller. It sets the status, generates a flash message, handles redirection, pushes it all to the front and comes with predefined helpers for enabling request-specs.
|
6
6
|
|
7
|
+
And build it dynamically: Most [turbo_power](https://github.com/marcoroth/turbo_power) commands, such as adding a css class to an html element or pushing a state to the browser history, work directly from the controller. Since turbo allows it, custom javascript functions are also possible.
|
8
|
+
|
7
9
|
An overview of how we design a rails-7 application with turbo
|
8
10
|
is [published on dev.to](https://dev.to/chmich/rails-7-vite-wrapping-up-1pia).
|
9
11
|
|
@@ -62,10 +64,10 @@ def update
|
|
62
64
|
end
|
63
65
|
```
|
64
66
|
|
65
|
-
This will set a status, generate a flash message and perform `
|
67
|
+
This will set a status, generate a flash message and perform `render_turbo_stream`, which could result in something like this:
|
66
68
|
|
67
69
|
```ruby
|
68
|
-
|
70
|
+
render_turbo_stream(
|
69
71
|
[
|
70
72
|
{
|
71
73
|
id: 'form',
|
@@ -80,7 +82,7 @@ stream_partials(
|
|
80
82
|
)
|
81
83
|
```
|
82
84
|
|
83
|
-
The `stream_partial` method is nothing else than a singular of `
|
85
|
+
The `stream_partial` method is nothing else than a singular of `render_turbo_stream`.
|
84
86
|
|
85
87
|
**locals**: The hash for locals goes through a `symbolize_keys`, so you need to use locals in used partials like this: `locals[:message]`.
|
86
88
|
|
@@ -93,13 +95,39 @@ stream_partial(
|
|
93
95
|
)
|
94
96
|
```
|
95
97
|
|
98
|
+
## More options
|
99
|
+
|
100
|
+
`render_turbo_stream` interprets a hash as a partial to be sent by `turbo_stream` and an array as a command to be sent. This should allow you to perform most actions from, for example, [turbo_power](https://github.com/marcoroth/turbo_power). An example of rendering a partial and adding a css class to an html element would look like this:
|
101
|
+
|
102
|
+
```ruby
|
103
|
+
render_turbo_stream(
|
104
|
+
[
|
105
|
+
{
|
106
|
+
id: 'form',
|
107
|
+
partial: 'form'
|
108
|
+
},
|
109
|
+
[
|
110
|
+
:add_css_class,
|
111
|
+
'#colored-element',
|
112
|
+
'red'
|
113
|
+
]
|
114
|
+
]
|
115
|
+
)
|
116
|
+
```
|
117
|
+
|
118
|
+
which is done under the hood, for the array: `= turbo_stream.send args.first, *(args[1..-1])`
|
119
|
+
|
120
|
+
|
96
121
|
## Testing Scenarios
|
97
122
|
|
98
123
|
For system testing there is Capybara. Its the only way to check if frontend and backend work together. But its a good practice to break tests into smaller pieces. The much larger number of tests we will write on the much faster request tests, examples here in rspec.
|
99
124
|
|
100
125
|
If the request format is not `turbo_stream`, which is the case on request specs, the method responds in a special html
|
101
|
-
that contains the medadata that is interesting for our tests and is parsed by included test helpers.
|
102
|
-
|
126
|
+
that contains the medadata that is interesting for our tests and is parsed by included test helpers.
|
127
|
+
|
128
|
+
There is a helper for writing the test: In the debugger, within the test, check the output of `partials_log`.
|
129
|
+
|
130
|
+
Test scenarios are:
|
103
131
|
|
104
132
|
**The fastest**
|
105
133
|
|
@@ -143,9 +171,7 @@ expect(partial_response('articles/form', id: 'form', css: '.field_with_errors',
|
|
143
171
|
|
144
172
|
**More detailed**
|
145
173
|
|
146
|
-
Consider a controller action that should respond in 2 flashes
|
147
|
-
|
148
|
-
Helper for writing the test: On Debugger, inside the test, check the output of `partials_log`.
|
174
|
+
Consider a controller action that should respond in 2 flashes:
|
149
175
|
|
150
176
|
```ruby
|
151
177
|
expect(partials_count).to eq(1)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<% rendered_partials = [] %>
|
2
|
+
|
3
|
+
<% streams.each do |s| %>
|
4
|
+
|
5
|
+
<% if s.is_a?(Array) %>
|
6
|
+
<% rendered_partials.push({ command: "turbo_stream.#{s.first}, #{s[1..-1].join(', ')}", method: s.first, attributes: s[1..-1] }) %>
|
7
|
+
<% else %>
|
8
|
+
<% html = (render s[:partial], locals: s[:locals]&.symbolize_keys, formats: [:html]) %>
|
9
|
+
<% rendered_partials.push({ html_response: html }.merge(s)) %>
|
10
|
+
<% end %>
|
11
|
+
|
12
|
+
|
13
|
+
<% end %>
|
14
|
+
|
15
|
+
<%= content_tag :div, rendered_partials.to_json, id: 'rendered-partials' %>
|
16
|
+
|
@@ -0,0 +1,41 @@
|
|
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
|
+
<% Rails.logger.error(" RENDER TURBO STREAM => #{ctl}") %>
|
11
|
+
<%= turbo_stream.send args.first, *(args[1..-1]) %>
|
12
|
+
|
13
|
+
|
14
|
+
<% else %>
|
15
|
+
<% ctl = { partial: args[:partial], id: args[:id], action: args[:action] } %>
|
16
|
+
<% info = { id: args[:id], partial: args[:partial], locals: args[:locals] } %>
|
17
|
+
<% if !args[:action].present? %>
|
18
|
+
<% Rails.logger.error(" ERROR RENDER TURBO STREAM => MISSING ACTION => #{args}") %>
|
19
|
+
<% error = true %>
|
20
|
+
|
21
|
+
<% elsif args[:action].present? %>
|
22
|
+
<% Rails.logger.debug(" • render-turbo-stream #{args[:action].upcase} => #{info}") %>
|
23
|
+
<%= turbo_stream.send args[:action].to_sym, args[:id] do %>
|
24
|
+
<%= render args[:partial], locals: args[:locals]&.symbolize_keys %>
|
25
|
+
<% end %>
|
26
|
+
|
27
|
+
<% else %>
|
28
|
+
<% Rails.logger.error(" ERROR RENDER TURBO STREAM => NOTHING DONE! => #{args}") %>
|
29
|
+
<% end %>
|
30
|
+
<% end %>
|
31
|
+
|
32
|
+
<% control.push(ctl) %>
|
33
|
+
|
34
|
+
<% end %>
|
35
|
+
|
36
|
+
<% if error %>
|
37
|
+
<% Rails.logger.error(" RENDER TURBO STREAM HAD ERRORS, REPEATING WHOLE ARRAY: ") %>
|
38
|
+
<% control.each do |c| %>
|
39
|
+
<% Rails.logger.error(" #{c}") %>
|
40
|
+
<% end %>
|
41
|
+
<% end %>
|
@@ -34,9 +34,18 @@ module RenderTurboStream
|
|
34
34
|
|
35
35
|
# Returns the path to which turbo_stream.redirect_to would be applied.
|
36
36
|
def turbo_redirect_to
|
37
|
-
|
38
|
-
|
39
|
-
r
|
37
|
+
resps = RenderTurboStream::Libs.all_responses(response)
|
38
|
+
url = nil
|
39
|
+
resps.each do |r|
|
40
|
+
if r['method'] == 'redirect_to'
|
41
|
+
if url
|
42
|
+
url = 'ERROR: REDIRECT CALLED MORE THAN ONCE'
|
43
|
+
else
|
44
|
+
url = r['attributes'].first
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
url
|
40
49
|
end
|
41
50
|
|
42
51
|
def partial_response_count(partial, id: nil, total: 1, &block)
|
data/lib/render_turbo_stream.rb
CHANGED
@@ -126,52 +126,42 @@ module RenderTurboStream
|
|
126
126
|
response.status = 302
|
127
127
|
flash[:alert] = flash_alerts
|
128
128
|
flash[:notice] = flash_notices
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
129
|
+
render_turbo_stream([
|
130
|
+
[
|
131
|
+
:redirect_to,
|
132
|
+
redirect_on_success_to
|
133
|
+
]
|
134
|
+
])
|
134
135
|
else
|
135
136
|
flash.now[:alert] = flash_alerts
|
136
137
|
flash.now[:notice] = flash_notices
|
137
|
-
|
138
|
+
render_turbo_stream(streams)
|
138
139
|
end
|
139
140
|
end
|
140
141
|
|
141
|
-
def
|
142
|
+
def render_turbo_stream(array)
|
142
143
|
|
143
144
|
ary = []
|
144
|
-
array.
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
145
|
+
array.each do |pr|
|
146
|
+
if pr.is_a?(Hash)
|
147
|
+
props = pr.symbolize_keys
|
148
|
+
part = (props[:partial].present? ? props[:partial] : props[:id]).gsub('-', '_')
|
149
|
+
partial = (part.to_s.include?('/') ? part : [controller_path, part].join('/'))
|
150
|
+
r = props
|
151
|
+
r[:action] = (props[:action].present? ? props[:action] : :replace)
|
152
|
+
r[:partial] = partial
|
153
|
+
ary.push(r)
|
154
|
+
elsif pr.is_a?(Array)
|
155
|
+
ary.push(pr)
|
156
|
+
else
|
157
|
+
raise "ERROR render_turbo_stream invalid type: Only hash or array allowed"
|
158
|
+
end
|
152
159
|
end
|
153
160
|
|
154
161
|
if request.format.to_sym == :turbo_stream
|
155
|
-
render template: '
|
162
|
+
render template: 'render_turbo_stream', locals: { streams: ary }, layout: false, formats: :turbo_stream
|
156
163
|
else
|
157
|
-
|
158
|
-
check_ids = {}
|
159
|
-
ary.each do |a|
|
160
|
-
if a[:action] == 'replace'
|
161
|
-
check_ids[a[:id]] ||= 0
|
162
|
-
check_ids[a[:id]] += 1
|
163
|
-
throw "More than one partial rendered to ID «#{a[:id]}» by replace" if check_ids[a[:id]] >= 2
|
164
|
-
end
|
165
|
-
end
|
166
|
-
end
|
167
|
-
check = {}
|
168
|
-
ary.each do |a|
|
169
|
-
b = a.dup
|
170
|
-
b.delete(:id)
|
171
|
-
check[a[:id]] = b
|
172
|
-
end
|
173
|
-
# render json: check
|
174
|
-
render template: 'render_turbo_stream_partials', locals: { check: check, streams: ary }, layout: false, formats: :html
|
164
|
+
render template: 'render_turbo_stream', locals: { streams: ary }, layout: false, formats: :html
|
175
165
|
end
|
176
166
|
end
|
177
167
|
|
@@ -181,7 +171,7 @@ module RenderTurboStream
|
|
181
171
|
action: :replace,
|
182
172
|
locals: {}
|
183
173
|
)
|
184
|
-
|
174
|
+
render_turbo_stream(
|
185
175
|
[
|
186
176
|
{
|
187
177
|
id: id,
|
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
|
+
version: 1.3.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-04-
|
11
|
+
date: 2023-04-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -24,10 +24,11 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 7.0.4.3
|
27
|
-
description:
|
27
|
+
description: Writing views like (create|update).turbo_stream.haml annoyed me. This
|
28
28
|
gem handles translated flash messages, sets status, and renders partials through
|
29
|
-
turbo-stream. You can control
|
30
|
-
|
29
|
+
turbo-stream. You can control it directly from the controller. With the turbo_power
|
30
|
+
gem you can also handle predefined actions like redirects and much more. Includes
|
31
|
+
helpers for enabling request testing.
|
31
32
|
email:
|
32
33
|
- christian@sedlmair.ch
|
33
34
|
executables: []
|
@@ -37,9 +38,8 @@ files:
|
|
37
38
|
- README.md
|
38
39
|
- Rakefile
|
39
40
|
- app/controllers/render_turbo_stream/application_controller.rb
|
40
|
-
- app/views/
|
41
|
-
- app/views/
|
42
|
-
- app/views/render_turbo_stream_redirect.turbo_stream.erb
|
41
|
+
- app/views/render_turbo_stream.html.erb
|
42
|
+
- app/views/render_turbo_stream.turbo_stream.erb
|
43
43
|
- lib/render_turbo_stream.rb
|
44
44
|
- lib/render_turbo_stream/engine.rb
|
45
45
|
- lib/render_turbo_stream/railtie.rb
|
@@ -72,6 +72,6 @@ requirements: []
|
|
72
72
|
rubygems_version: 3.4.12
|
73
73
|
signing_key:
|
74
74
|
specification_version: 4
|
75
|
-
summary: Render partials by turbo-stream directly
|
76
|
-
included.
|
75
|
+
summary: Render partials or performing javascript actions by turbo-stream directly
|
76
|
+
from the controller. Test helpers included.
|
77
77
|
test_files: []
|
@@ -1,12 +0,0 @@
|
|
1
|
-
<% rendered_partials = [] %>
|
2
|
-
|
3
|
-
<% streams.each do |s| %>
|
4
|
-
|
5
|
-
<% html = (render s[:partial], locals: s[:locals]&.symbolize_keys, formats: [:html]) %>
|
6
|
-
|
7
|
-
<% rendered_partials.push({ html_response: html }.merge(s)) %>
|
8
|
-
|
9
|
-
<% end %>
|
10
|
-
|
11
|
-
<%= content_tag :div, rendered_partials.to_json, id: 'rendered-partials' %>
|
12
|
-
|
@@ -1,52 +0,0 @@
|
|
1
|
-
<% error = false %>
|
2
|
-
<% control = [] %>
|
3
|
-
<% local_assigns[:streams].each do |s| %>
|
4
|
-
<% ctl = { partial: s[:partial], id: s[:id] } %>
|
5
|
-
<% info = { id: s[:id], partial: s[:partial], locals: s[:locals] } %>
|
6
|
-
|
7
|
-
<% if !s[:id] %>
|
8
|
-
<% Rails.logger.error(" ERROR RENDER TURBO STREAM => MISSING ID => #{s}") %>
|
9
|
-
<% error = true %>
|
10
|
-
|
11
|
-
<% elsif !s[:partial].present? %>
|
12
|
-
<% Rails.logger.error(" ERROR RENDER TURBO STREAM => MISSING PARTIAL => #{s}") %>
|
13
|
-
<% error = true %>
|
14
|
-
<% ctl[:partial] = nil %>
|
15
|
-
|
16
|
-
<% elsif s[:action].to_sym == :replace %>
|
17
|
-
<% ctl[:action] = :replace %>
|
18
|
-
<% Rails.logger.debug(" • render-turbo-stream REPLACE => #{info}") %>
|
19
|
-
<%= turbo_stream.replace s[:id] do %>
|
20
|
-
<%= render s[:partial], locals: s[:locals]&.symbolize_keys %>
|
21
|
-
<% end %>
|
22
|
-
|
23
|
-
<% elsif s[:action].to_sym == :prepend %>
|
24
|
-
<% ctl[:action] = :prepend %>
|
25
|
-
<% Rails.logger.debug(" • render-turbo-stream PREPEND => #{info}") %>
|
26
|
-
<%= turbo_stream.prepend s[:id] do %>
|
27
|
-
<%= render s[:partial], locals: s[:locals]&.symbolize_keys %>
|
28
|
-
<% end %>
|
29
|
-
|
30
|
-
<% elsif s[:action].to_sym == :append %>
|
31
|
-
<% ctl[:action] = :append %>
|
32
|
-
<% Rails.logger.debug(" • render-turbo-stream APPEND => #{info}") %>
|
33
|
-
<%= turbo_stream.prepend s[:id] do %>
|
34
|
-
<%= render s[:partial], locals: s[:locals]&.symbolize_keys %>
|
35
|
-
<% end %>
|
36
|
-
|
37
|
-
<% else %>
|
38
|
-
<% ctl[:action] = :UNKNOWN %>
|
39
|
-
<% Rails.logger.fatal(" ERROR render-turbo-stream => UNKNOWN ACTION => #{s}") %>
|
40
|
-
<% error = true %>
|
41
|
-
<% end %>
|
42
|
-
|
43
|
-
<% control.push(ctl) %>
|
44
|
-
|
45
|
-
<% end %>
|
46
|
-
|
47
|
-
<% if error %>
|
48
|
-
<% Rails.logger.error(" RENDER TURBO STREAM HAD ERRORS, REPEATING WHOLE ARRAY: ") %>
|
49
|
-
<% control.each do |c| %>
|
50
|
-
<% Rails.logger.error(" #{c}") %>
|
51
|
-
<% end %>
|
52
|
-
<% end %>
|
@@ -1 +0,0 @@
|
|
1
|
-
<%= turbo_stream.redirect_to local_assigns[:url] %>
|