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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: dd9433b4adbd71cc1c6200b10b969c3692772f4cc8a4b21e0e02948e58104a3a
4
- data.tar.gz: 21f9ba3336cdc8875300738885eee417a971fe4f6364c81ca9e772579ba80f10
3
+ metadata.gz: 7737e1e5b1a6b397c22634b0a7efe6ee3f5d550a041fc667323c3b91dc5bf31b
4
+ data.tar.gz: a254e95ff504444aec88dfb25bfeb24c30f10447b2f47bfe7ff40ef57bb3ed0b
5
5
  SHA512:
6
- metadata.gz: e50b4ec7e474c6f8c4476f49eb97e6d1088308182d1b3d9d7ecb31fcbc491a940b6cf71046c4626cca36f8234e3008fc09b8bf6ae8ac12473ca04c795cf8faea
7
- data.tar.gz: a5c91d74dce4bc5031da22fa702a74d3a8e5eff0aa19ed7bdd7296a9dc6e369c0e7a51cdfb964c316a4f3bddc12c3635af557113ae1d96d7f67d4715fb16cced
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 `stream_partials`, which could result in something like this:
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
- stream_partials(
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 `stream_partials`.
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. So tests could look
102
- like this:
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
- expect(response.status).to eq(302)
38
- r = JSON.parse(response.body)
39
- r['redirected_to']
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)
@@ -1,3 +1,3 @@
1
1
  module RenderTurboStream
2
- VERSION = "1.2.2"
2
+ VERSION = "1.3.0"
3
3
  end
@@ -126,52 +126,42 @@ module RenderTurboStream
126
126
  response.status = 302
127
127
  flash[:alert] = flash_alerts
128
128
  flash[:notice] = flash_notices
129
- if request.format.to_sym == :turbo_stream
130
- render template: 'render_turbo_stream_redirect', locals: { url: redirect_on_success_to }, layout: false
131
- else
132
- render json: { redirected_to: redirect_on_success_to }
133
- end
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
- stream_partials(streams)
138
+ render_turbo_stream(streams)
138
139
  end
139
140
  end
140
141
 
141
- def stream_partials(array)
142
+ def render_turbo_stream(array)
142
143
 
143
144
  ary = []
144
- array.dup.each do |pr|
145
- props = pr.symbolize_keys
146
- part = (props[:partial].present? ? props[:partial] : props[:id]).gsub('-', '_')
147
- partial = (part.to_s.include?('/') ? part : [controller_path, part].join('/'))
148
- r = props
149
- r[:action] = (props[:action].present? ? props[:action] : :replace)
150
- r[:partial] = partial
151
- ary.push(r)
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: 'render_turbo_stream_partials', locals: { streams: ary }, layout: false
162
+ render template: 'render_turbo_stream', locals: { streams: ary }, layout: false, formats: :turbo_stream
156
163
  else
157
- if Rails.env.test?
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
- stream_partials(
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.2.2
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-21 00:00:00.000000000 Z
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: 'Writing views like (create|update).turbo_stream.haml annoyed me. This
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 them directly from the controller. It also handles
30
- redirection: turbo_power is included. Includes helpers for enabling request testing.'
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/render_turbo_stream_partials.html.erb
41
- - app/views/render_turbo_stream_partials.turbo_stream.erb
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 from the controller. Test helpers
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] %>