render_turbo_stream 1.3.3 → 1.4.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b32041ebda04bf085c6199ba1e29e5274f9fa86c2a210c7ee6a32e9937721037
4
- data.tar.gz: 32b05f420b1ce6c6733615f2be5059a265ee58bf2c55269363aa14e0d0f41c2e
3
+ metadata.gz: cf65f7ac19c9387a4ee6a42f9e2227082ec7996aef74e672cc45aa04f75becf7
4
+ data.tar.gz: 558ecbee422b8eab39c292f82ae0df3df54cc5b439b0e8a7b83008dc863e00ec
5
5
  SHA512:
6
- metadata.gz: bfdd0158be7131cdd05e7527b7005b40d90621d9a95919955bdeb58dd0e75cb41d5e7799ad43626f05d690a814600f267b9476e25e3a5b7400be6a8d36a481dd
7
- data.tar.gz: f04d228c519cd617ff53e7292144673eaaf610e879f87fc4a95a6902e487bffab7a84bd0bbff3068a94f138b2c32a17ea91872e45f117c133f1f846029cf3ede
6
+ metadata.gz: 11549d8a9b8145ca04e7e025516a74edbeeb726bfa9d3bfca0fa819c2d8bf76da7d354c860ec01ec461b4d50b80e0fb197aaf34b30502b1d29d72718982cf149
7
+ data.tar.gz: 8405143aeae7793da5011b56e5993843dac2f0f97c5d0cce712d5fac0eca5a1e4045dd7680b72db76f6c5c761dd35f7f3fa24fb71e029dbde6bda8b49b140281
data/README.md CHANGED
@@ -6,6 +6,8 @@ Working consistently with turbo_stream means shooting lots of partials from the
6
6
 
7
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
8
 
9
+ ATTENTION: This plugin is in a early state.
10
+
9
11
  An overview of how we design a rails-7 application with turbo
10
12
  is [published on dev.to](https://dev.to/chmich/rails-7-vite-wrapping-up-1pia).
11
13
 
@@ -34,11 +36,6 @@ RSpec.configure do |config|
34
36
  end
35
37
  ```
36
38
 
37
- **Redirection and more**
38
-
39
- For redirection to work, you must follow the installation steps
40
- from [turbo_power](https://github.com/marcoroth/turbo_power).
41
-
42
39
  **Flash**
43
40
 
44
41
  Required Configurations for Flash Partial
@@ -51,16 +48,37 @@ config.x.render_turbo_stream.flash_action = 'prepend'
51
48
 
52
49
  The corresponding partials for flashes could look [like this](https://gitlab.com/sedl/renderturbostream/-/wikis/flashes)
53
50
 
51
+ **Translations**
52
+
53
+ ```
54
+ activerecord.success.successfully_created
55
+ activerecord.success.successfully_updated
56
+ activerecord.errors.messages.could_not_create
57
+ activerecord.errors.messages.could_not_update
58
+ ```
59
+
60
+ example value: `"%<model_name>s successfully created"`
61
+
62
+ Model name translations, see: Rails Docs.
63
+
64
+ **Turbo power**
65
+
66
+ To get redirection and many other options working, you need to follow the installation steps from [turbo_power](https://github.com/marcoroth/turbo_power).
67
+
68
+ **Turbo itself**
69
+
70
+ A comprehensive tutorial on turbo and how to check that it is working properly can be found at [hotrails.dev](https://www.hotrails.dev/turbo-rails).
71
+
54
72
  ## Usage
55
73
 
56
- `turbo_stream_save` is a special method for streamlining `update' or `create' functions with `turbo_stream'. A controller action for update might look like this:
74
+ `turbo_stream_save` is a special method for streamlining `update` or `create` functions with `turbo_stream`. A controller action for update might look like this:
57
75
 
58
76
  ```ruby
59
77
 
60
78
  def update
61
79
  turbo_stream_save(
62
80
  @customer.update(customer_params),
63
- redirect_on_success_to: edit_customer_path(@customer)
81
+ redirect_on_success_to: edit_customer_path(@customer),
64
82
  )
65
83
  end
66
84
  ```
@@ -72,7 +90,7 @@ render_turbo_stream(
72
90
  [
73
91
  {
74
92
  id: 'form',
75
- partial: 'form'
93
+ partial: 'customers/form'
76
94
  },
77
95
  {
78
96
  id: 'flash-wrapper',
@@ -96,7 +114,7 @@ stream_partial(
96
114
 
97
115
  **locals**: The hash for locals goes through a `symbolize_keys`, so you need to use locals in used partials like this: `locals[:message]`.
98
116
 
99
- ## More options
117
+ **More options**
100
118
 
101
119
  `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 allows you to perform most actions from e.g. [turbo_power](https://github.com/marcoroth/turbo_power). An example of adding a css class to an html element and updating the browser history would look like this:
102
120
 
@@ -111,12 +129,45 @@ render_turbo_stream(
111
129
  :add_css_class,
112
130
  '#colored-element',
113
131
  'red'
132
+ ],
133
+ [
134
+
114
135
  ]
115
136
  ]
116
137
  )
117
138
  ```
118
139
 
119
- which is done under the hood, for the array: `= turbo_stream.send args.first, *(args[1..-1])`
140
+ Under the hood, inside a `*.turbo_stream.erb` template, it does the following: `= turbo_stream.send args.first, *(args[1..-1])`
141
+
142
+ **Parameters for turbo_stream_save**
143
+
144
+ save_action,
145
+ redirect_on_success_to: nil,
146
+ object: nil, # object used in save_action, example: @customer
147
+ id: 'form', # if nil: no partial is rendered
148
+ partial: nil, # example: 'customers/form' default: "#{controller_path}/#{id}"
149
+ action: 'replace', # options: append, prepend
150
+ locals: {}, # locals used by the partial
151
+ streams_on_success: [
152
+ {
153
+ id: nil,
154
+ partial: 'form',
155
+ locals: {},
156
+ action: 'replace'
157
+ }
158
+ ], # additional partials that should be rendered if save_action succeeded
159
+ streams_on_error: [
160
+ {
161
+ id: nil,
162
+ partial: 'form',
163
+ locals: {},
164
+ action: 'replace'
165
+ }
166
+ ], # additional partials that should be rendered if save_action failed
167
+ add_flash_alerts: [], #=> array of strings
168
+ add_flash_notices: [], #=> array of strings
169
+ flashes_on_success: [], #=> array of strings
170
+ flashes_on_error: [] #=> array of strings
120
171
 
121
172
 
122
173
  ## Testing Scenarios
@@ -126,7 +177,7 @@ For system testing there is Capybara. Its the only way to check if frontend and
126
177
  If the request format is not `turbo_stream`, which is the case on request specs, the method responds in a special html
127
178
  that contains the medadata that is interesting for our tests and is parsed by included test helpers.
128
179
 
129
- There is a helper for writing the test: In the debugger, within the test, check the output of `partials_log`.
180
+ There is a helper for writing the test: In the debugger, within the test, check the output of `streams_log`.
130
181
 
131
182
  Test scenarios are:
132
183
 
@@ -141,10 +192,10 @@ For rspec there is a special helper, for a successful save action:
141
192
  ```ruby
142
193
  it 'update failed' do
143
194
  patch article_path(article, params: valid_params)
144
- expect_successful_saved('form', 'flash-box')
195
+ expect_successful_saved('customer-form', 'flash-box')
145
196
  # expects response.status 200
146
197
  # Make sure that the responses point to exactly these 2 IDs ('form' and 'flash-box').
147
- # Make sure that each ID is responded to exactly once.
198
+ # Make sure that to each ID is responded to exactly once.
148
199
  end
149
200
  ```
150
201
 
@@ -160,14 +211,14 @@ end
160
211
 
161
212
  For checking a little more inside the partial responses, but with a simple syntax that checks for a one-time response from a specific partial and may be sufficient for most cases:
162
213
  ```ruby
163
- expect(partials_count).to eq(2)
164
- # Check the total number of responding partials, in most cases it will be one form and one flash.
214
+ expect(stream_targets_count).to eq(2)
215
+ # Check the total number of targeted html-ids, in most cases it will be one form and one flash.
165
216
 
166
- expect(partial_response('form')).to eq(true)
167
- # Make sure that the form part (controller_path is not checked) has responded exactly once.
217
+ expect(stream_response('customer-form')).to eq(true)
218
+ # Make sure that the id «customer-form» is targeted exactly once.
168
219
 
169
- expect(partial_response('articles/form', id: 'form', css: '.field_with_errors', include_string: 'Title')).to eq(true)
170
- # Check the content inside at least one in any of the elements that match the given css and check the id that turbo has pointed to..
220
+ expect(stream_response('customer-form', css: '.field_with_errors', include_string: 'Title')).to eq(true)
221
+ # Verify that the response targeted to "customer-form" contains the specified html.
171
222
  ```
172
223
 
173
224
  **More detailed**
@@ -175,77 +226,31 @@ expect(partial_response('articles/form', id: 'form', css: '.field_with_errors',
175
226
  Consider a controller action that should respond in 2 flashes:
176
227
 
177
228
  ```ruby
178
- expect(partials_count).to eq(1)
229
+ expect(stream_targets_count).to eq(1)
179
230
 
180
231
  expect(
181
- partial_response_count('flash', total: 2) do |p|
232
+ stream_target_response_count('flash-box', total: 2) do |p|
182
233
  p.css('.callout.success').inner_html.include?('All perfect')
183
234
  end
184
235
  ).to eq(1)
185
236
 
186
237
  expect(
187
- partial_response_count('layouts/flash', id: 'flash-box', total: 2) do |p|
238
+ stream_target_response_count('flash-box', total: 2) do |p|
188
239
  p.css('.callout.alert').inner_html.include?('Something went wrong')
189
240
  end
190
241
  ).to eq(1)
191
242
  ```
192
- `partial_response_count` always returns the number of matched responses.
243
+ `stream_target_response_count` returns the number of matched responses.
244
+
245
+ Possible matchers can be found at [Nokogiri](https://nokogiri.org/tutorials/searching_a_xml_html_document.html).
193
246
 
194
- Possible matchers can be found at [Nokogiri](https://nokogiri.org/tutorials/searching_a_xml_html_document.html). That should be enough for this level. For more detailed testing of partials, there are view tests. And many of the partials are regularly accessed in two ways, for example a `form': it is pushed by turbo_stream as well as by calling edit_customer_path.
247
+ For more detailed testing of partials, there are view tests.
195
248
 
196
- P.S.:
249
+ **P.S.:**
197
250
 
198
251
  Testing the plugin itself: There is a [quick-and-dirty app](https://gitlab.com/sedl/renderturbostream_railsapp) which
199
252
  includes the plugin and has tests done by rspec/request and capybara.
200
253
 
201
- ## Parameters for turbo_stream_save
202
-
203
- save_action,
204
- redirect_on_success_to: nil,
205
- object: nil, # object used in save_action, example: @customer
206
- id: 'form', # if nil: no partial is rendered
207
- partial: nil, # example: 'customers/form' default: "#{controller_path}/#{id}"
208
- action: 'replace', # options: append, prepend
209
- locals: {}, # locals used by the partial
210
- streams_on_success: [
211
- {
212
- id: nil,
213
- partial: 'form',
214
- locals: {},
215
- action: 'replace'
216
- }
217
- ], # additional partials that should be rendered if save_action succeeded
218
- streams_on_error: [
219
- {
220
- id: nil,
221
- partial: 'form',
222
- locals: {},
223
- action: 'replace'
224
- }
225
- ], # additional partials that should be rendered if save_action failed
226
- add_flash_alerts: [], #=> array of strings
227
- add_flash_notices: [], #=> array of strings
228
- flashes_on_success: [], #=> array of strings
229
- flashes_on_error: [] #=> array of strings
230
-
231
- ## Requirements
232
-
233
- gem `turbo_power` (is included, used for redirection)
234
-
235
- **Translations**
236
-
237
- `activerecord.success.successfully_created`
238
-
239
- `activerecord.success.successfully_updated`
240
-
241
- `activerecord.errors.messages.could_not_create`
242
-
243
- `activerecord.errors.messages.could_not_update`
244
-
245
- example value: `"%<model_name>s successfully created"`
246
-
247
- .. and Model Name Translations
248
-
249
254
  ## Contributing
250
255
 
251
256
  Contribution welcome.
@@ -0,0 +1,49 @@
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 %>
@@ -6,6 +6,7 @@
6
6
  <% rendered_partials.push({ command: "turbo_stream.#{s.first}, #{s[1..-1].join(', ')}", method: s.first, attributes: s[1..-1] }) %>
7
7
  <% else %>
8
8
  <% html = (render s[:partial], locals: s[:locals]&.symbolize_keys, formats: [:html]) %>
9
+ <% s.delete(:partial) %>
9
10
  <% rendered_partials.push({ html_response: html }.merge(s)) %>
10
11
  <% end %>
11
12
 
@@ -2,16 +2,8 @@ module RenderTurboStream
2
2
  module Test
3
3
  module RequestHelpers
4
4
 
5
- # count of rendered partials
6
- # count rendering different partials (example: «customer/form»)
7
- # doesnt check how often a specific partial is rendered
8
-
9
- def partials_count
10
- RenderTurboStream::Libs.partials_count(response)
11
- end
12
-
13
5
  # log as helper for the developer to see which flash is set and which partials are rendered to wich ids
14
- def partials_log
6
+ def streams_log
15
7
  all_responses = RenderTurboStream::Libs.all_responses(response)
16
8
  r = []
17
9
  if response.status == 302
@@ -48,12 +40,12 @@ module RenderTurboStream
48
40
  url
49
41
  end
50
42
 
51
- def partial_response_count(partial, id: nil, total: 1, &block)
52
- RenderTurboStream::Libs.partial_response_count(response, partial, id, total, &block)
43
+ def stream_target_response_count(id, total: 1, &block)
44
+ RenderTurboStream::Libs.stream_target_response_count(response, id, total, &block)
53
45
  end
54
46
 
55
- def partial_response(partial, id: nil, css: nil, include_string: nil)
56
- c = partial_response_count(partial, id: id, total: 1) do |r|
47
+ def stream_response(id, css: nil, include_string: nil)
48
+ c = stream_target_response_count(id, total: 1) do |r|
57
49
  if css && include_string
58
50
  r.css(css).inner_html.include?(include_string)
59
51
  elsif include_string
@@ -67,8 +59,12 @@ module RenderTurboStream
67
59
  c == 1
68
60
  end
69
61
 
70
- def partial_ids
71
- RenderTurboStream::Libs.partial_ids(response)
62
+ def stream_targets
63
+ RenderTurboStream::Libs.stream_targets(response)
64
+ end
65
+
66
+ def stream_targets_count
67
+ stream_targets.length
72
68
  end
73
69
  end
74
70
  end
@@ -1,3 +1,3 @@
1
1
  module RenderTurboStream
2
- VERSION = "1.3.3"
2
+ VERSION = "1.4.2"
3
3
  end
@@ -8,7 +8,8 @@ module RenderTurboStream
8
8
 
9
9
  def turbo_stream_save(
10
10
  save_action,
11
- redirect_on_success_to: nil,
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
12
+ turbo_redirect_on_success_to: nil, # does a full page redirect (break out of all frames by turbo_power redirect)
12
13
  object: nil, # object used in save_action, example: @customer
13
14
  id: 'form', # if nil: no partial is rendered
14
15
  partial: nil, # example: 'customers/form' default: "#{controller_path}/#{id}"
@@ -122,16 +123,27 @@ module RenderTurboStream
122
123
 
123
124
  #== render
124
125
 
125
- if save_action && redirect_on_success_to.present?
126
+ if save_action && turbo_redirect_on_success_to.present?
126
127
  response.status = 302
127
128
  flash[:alert] = flash_alerts
128
129
  flash[:notice] = flash_notices
129
- render_turbo_stream([
130
- [
131
- :redirect_to,
132
- redirect_on_success_to
133
- ]
134
- ])
130
+ render_turbo_stream([
131
+ [
132
+ :redirect_to,
133
+ turbo_redirect_on_success_to
134
+ ]
135
+ ])
136
+ elsif save_action && redirect_on_success_to.present?
137
+ response.status = 302
138
+ flash.now[:alert] = flash_alerts
139
+ flash.now[:notice] = flash_notices
140
+ render_turbo_stream([
141
+ [
142
+ :redirect_to,
143
+ turbo_redirect_on_success_to
144
+ ]
145
+ ])
146
+
135
147
  else
136
148
  flash.now[:alert] = flash_alerts
137
149
  flash.now[:notice] = flash_notices
@@ -191,40 +203,20 @@ module RenderTurboStream
191
203
 
192
204
  # if partial is one word, its checked against the last behind the slash, example: 'articles/form' matches 'form'
193
205
 
194
- def self.select_responses(response, partial, id)
206
+ def self.select_responses(response, id)
195
207
  all = all_responses(response)
196
208
 
197
209
  all.select do |a|
198
- partial_matched = if !partial.present?
199
- false
200
- elsif partial.include?('/')
201
- a['partial'] == partial
202
- else
203
- a['partial'].split('/').last == partial
204
- end
205
- id_matched = if !id.present?
206
- false
207
- else
208
- a['id'] == id
209
- end
210
- partial_matched && (id.present? ? id_matched : true)
211
- end
212
-
213
- end
214
-
215
- def self.partials_count(response)
216
- all = all_responses(response)
217
- part = []
218
- all.each do |p|
219
- _p = p['partial']
220
- unless part.include?(_p)
221
- part.push(_p)
210
+ if id.present?
211
+ a['id'] == id
212
+ else
213
+ false
222
214
  end
223
215
  end
224
- part.length
216
+
225
217
  end
226
218
 
227
- def self.partial_ids(response)
219
+ def self.stream_targets(response)
228
220
  all = all_responses(response)
229
221
  ids = []
230
222
  all.each do |p|
@@ -236,8 +228,8 @@ module RenderTurboStream
236
228
  ids
237
229
  end
238
230
 
239
- def self.partial_response_count(response, partial, id, total, &block)
240
- responses = select_responses(response, partial, id)
231
+ def self.stream_target_response_count(response, id, total, &block)
232
+ responses = select_responses(response, id)
241
233
 
242
234
  if total && responses.count != total
243
235
  false
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.3.3
4
+ version: 1.4.2
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-23 00:00:00.000000000 Z
11
+ date: 2023-04-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -38,6 +38,7 @@ 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
41
42
  - app/views/render_turbo_stream.html.erb
42
43
  - app/views/render_turbo_stream.turbo_stream.erb
43
44
  - lib/render_turbo_stream.rb