render_turbo_stream 1.4.4 → 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: ab99348bf3118d88b5b5d1ae6bb12eca5c3b2a433c53ce8d7777a7519130f69c
4
- data.tar.gz: 57958c45f249bab4fb1c1d4c118a5a30db4956f2991c04bca9ac36b50739e78f
3
+ metadata.gz: 0c77fc6dda3c5b3edc629f63a7f572835b1e6c5c4e22cd7708eb9d5dd4be99db
4
+ data.tar.gz: 83552375772d2a578a39fbca51b0ef586b47eb4eafc9de7a949a00472f61c78a
5
5
  SHA512:
6
- metadata.gz: 725ca7fb7f726dbb70c796ed8438ebf74ea63310055188c635bd94d59f5297f99c974d44677fc8b7bf2d033c07960fcc5ccb7c68cf1a0ebbbe5d868b0c9f2af4
7
- data.tar.gz: 7d2639a7744be4b9f9e28a620a7d2c55adedc7a2948b197ef4ced797d2ff585041cb9ffba61b72a55c87766fc803581098b7ad65595708dd76378d80e39b69e5
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
 
@@ -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
  )
@@ -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
- How to handle a classical redirect_to, together with a flash message, within a frame for a CRUD controller? see [workaround](https://gitlab.com/sedl/renderturbostream/-/issues/3)
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: 'form', # if nil: no partial is rendered
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.
@@ -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
 
@@ -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.4"
2
+ VERSION = "1.4.5"
3
3
  end
@@ -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 AT SAME TIME https://github.com/rails/rails/issues/48056
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 = [(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
@@ -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['id'] == id
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
- all = all_responses(response)
227
- ids = []
228
- all.each do |p|
229
- _p = p['id']
230
- unless ids.include?(_p)
231
- 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'])
232
235
  end
233
236
  end
234
- ids
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
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 %>