render_turbo_stream 1.4.3 → 1.4.5

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: 740e9df76f8c575bc3a993c3bc3ad524d70e1a4593c21906ca41d16dc426399b
4
- data.tar.gz: 6ea17ebf4b85712130b3b5289cecffcf76d043cb6d1638bfa68f27c7d1aa7494
3
+ metadata.gz: 0c77fc6dda3c5b3edc629f63a7f572835b1e6c5c4e22cd7708eb9d5dd4be99db
4
+ data.tar.gz: 83552375772d2a578a39fbca51b0ef586b47eb4eafc9de7a949a00472f61c78a
5
5
  SHA512:
6
- metadata.gz: 4dd54e9153f44bc4e6104132d75f1b7ad9613569f8f2c49c5b0a44711aacb6eac92c0c77a82bec52b82491b3450010fcffc581221340d5510c0f87bcf2650b74
7
- data.tar.gz: e337836ec7353f535236f6e9aac1b7aa4c514d3eb370464bfb6cc7499f32b41c3501c89146a864781b15ba6145d2849439fb91564676f9a0b3a2b197ea686455
6
+ metadata.gz: 9d6e8e06675b08dc65465da8424c918bb65757a2d8fa053ea5b6d9dc98bb452bdc152c350c08f80a762c0ab9c08d5afbdf7bf6aa3b65b4fe60a80bf4a8f197f7
7
+ data.tar.gz: ab8b0e8d42d0957e632881148b28f29e67c3380dc4e61191c54697c7a255d03b463d213bb494b780cc948be941da017d17a23b8758f6caa5d26e9b499b693ed4
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 it helps 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
 
@@ -78,7 +80,7 @@ A comprehensive tutorial on turbo and how to check that it is working properly c
78
80
  def update
79
81
  turbo_stream_save(
80
82
  @customer.update(customer_params),
81
- redirect_on_success_to: edit_customer_path(@customer),
83
+ turbo_redirect_on_success_to: edit_customer_path(@customer),
82
84
  )
83
85
  end
84
86
  ```
@@ -101,7 +103,7 @@ render_turbo_stream(
101
103
  )
102
104
  ```
103
105
 
104
- The `stream_partial` method is nothing else than a singular of `render_turbo_stream`.
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
  )
@@ -139,12 +138,36 @@ render_turbo_stream(
139
138
 
140
139
  Under the hood, inside a `*.turbo_stream.erb` template, it does the following: `= turbo_stream.send args.first, *(args[1..-1])`
141
140
 
141
+ **WORKAROUND for redirects inside frame**
142
+
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
+ ```
163
+
142
164
  **Parameters for turbo_stream_save**
143
165
 
144
166
  save_action,
145
- 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)
146
169
  object: nil, # object used in save_action, example: @customer
147
- id: 'form', # if nil: no partial is rendered
170
+ id: nil, # if nil: no partial is rendered
148
171
  partial: nil, # example: 'customers/form' default: "#{controller_path}/#{id}"
149
172
  action: 'replace', # options: append, prepend
150
173
  locals: {}, # locals used by the partial
@@ -251,6 +274,17 @@ For more detailed testing of partials, there are view tests.
251
274
  Testing the plugin itself: There is a [quick-and-dirty app](https://gitlab.com/sedl/renderturbostream_railsapp) which
252
275
  includes the plugin and has tests done by rspec/request and capybara.
253
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
+
254
288
  ## Contributing
255
289
 
256
290
  Contribution welcome.
@@ -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
- <% rendered_partials.push({ command: "turbo_stream.#{s.first}, #{s[1..-1].join(', ')}", method: s.first, attributes: s[1..-1] }) %>
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
- <% rendered_partials.push({ html_response: html }.merge(s)) %>
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
 
@@ -7,7 +7,7 @@
7
7
  <% if args.is_a?(Array) %>
8
8
 
9
9
  <% ctl = "turbo_stream.#{args.first}, #{args[1..-1].join(', ')}" %>
10
- <% Rails.logger.error(" RENDER TURBO STREAM => #{ctl}") %>
10
+ <% Rails.logger.debug(" RENDER TURBO STREAM => #{ctl}") %>
11
11
  <%= turbo_stream.send args.first, *(args[1..-1]) %>
12
12
 
13
13
 
@@ -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
- all_responses = RenderTurboStream::Libs.all_responses(response)
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['method'] == 'redirect_to'
33
- if url
34
- url = 'ERROR: REDIRECT CALLED MORE THAN ONCE'
35
- else
36
- url = r['attributes'].first
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
- counts = {}
9
+ id_counts = {}
11
10
  responses.each do |r|
12
- counts[r['id']] ||= 0
13
- counts[r['id']] +=1
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(counts.keys.length).to eq(ids.length)
25
+ expect(id_counts.keys.length).to eq(ids.length)
18
26
  ids.each do |id|
19
- expect(counts.key?(id)).to be_truthy
20
- expect(counts[id]).to eq(1)
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
 
@@ -1,3 +1,3 @@
1
1
  module RenderTurboStream
2
- VERSION = "1.4.3"
2
+ VERSION = "1.4.5"
3
3
  end
@@ -8,10 +8,10 @@ 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
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
- id: 'form', # if nil: no partial is rendered
14
+ id: nil, # if nil: no partial is rendered
15
15
  partial: nil, # example: 'customers/form' default: "#{controller_path}/#{id}"
16
16
  action: 'replace', # options: append, prepend
17
17
  locals: {}, # locals used by the partial
@@ -43,11 +43,19 @@ module RenderTurboStream
43
43
 
44
44
  #== Streams / Partials
45
45
 
46
- streams = [(id ? { id: id, partial: partial, locals: locals, action: action } : nil)]
46
+ streams = (id ? [id: id, partial: partial, locals: locals, action: action] : [])
47
47
 
48
48
  if save_action
49
49
  response.status = 200
50
- streams += streams_on_success.select { |s| s[:id].present? }
50
+ Rails.logger.debug('start loop')
51
+ streams_on_success.each do |s|
52
+ Rails.logger.debug('inside loop')
53
+ if s.is_a?(Array)
54
+ streams.push(s)
55
+ elsif s.is_a?(Hash) && s[:id].present?
56
+ streams.push(s)
57
+ end
58
+ end
51
59
  else
52
60
  response.status = :unprocessable_entity
53
61
  streams += streams_on_error.select { |s| s[:id].present? }
@@ -135,9 +143,9 @@ module RenderTurboStream
135
143
  ])
136
144
  elsif save_action && redirect_on_success_to.present?
137
145
  response.status = 302
138
- flash.now[:alert] = flash_alerts
139
- flash.now[:notice] = flash_notices
140
- render_turbo_stream(streams)
146
+ flash[:alert] = flash_alerts
147
+ flash[:notice] = flash_notices
148
+ # render_turbo_stream(streams)
141
149
  redirect_to redirect_on_success_to
142
150
 
143
151
  else
@@ -151,7 +159,9 @@ module RenderTurboStream
151
159
 
152
160
  ary = []
153
161
  array.each do |pr|
154
- if pr.is_a?(Hash)
162
+ if !pr.present?
163
+ a = 1
164
+ elsif pr.is_a?(Hash)
155
165
  props = pr.symbolize_keys
156
166
  part = (props[:partial].present? ? props[:partial] : props[:id]).gsub('-', '_')
157
167
  partial = (part.to_s.include?('/') ? part : [controller_path, part].join('/'))
@@ -204,7 +214,7 @@ module RenderTurboStream
204
214
 
205
215
  all.select do |a|
206
216
  if id.present?
207
- a['id'] == id
217
+ a['target'] == "##{id}"
208
218
  else
209
219
  false
210
220
  end
@@ -213,15 +223,19 @@ module RenderTurboStream
213
223
  end
214
224
 
215
225
  def self.stream_targets(response)
216
- all = all_responses(response)
217
- ids = []
218
- all.each do |p|
219
- _p = p['id']
220
- unless ids.include?(_p)
221
- ids.push(_p)
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'])
222
235
  end
223
236
  end
224
- ids
237
+
238
+ targets
225
239
  end
226
240
 
227
241
  def self.stream_target_response_count(response, id, total, &block)
@@ -242,5 +256,41 @@ module RenderTurboStream
242
256
 
243
257
  end
244
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
+
245
295
  end
246
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.3
4
+ version: 1.4.5
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-24 00:00:00.000000000 Z
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, run javascript like redirect by controller. With test helpers.
75
+ summary: Render partials and execute javascript directly from the controller. With
76
+ test 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 %>