render_turbo_stream 4.1.6 → 4.2.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: d41d763714ed2d599837c9cd3723d2f618f9ee6df7a095c8a06d0f66291cae7f
4
- data.tar.gz: fac83287dbba160bfbe7a18b505810eab430c0fef43b32472494ee3e3291acd2
3
+ metadata.gz: e0baf30f6152a1308687add8e14fda8ae815bfa43e54f9b4ffc6d859accc5e5b
4
+ data.tar.gz: a61f84ab272df1447b3a4cd38ef5dcbf3702390e360cbb03d5f172f0056aa760
5
5
  SHA512:
6
- metadata.gz: 4c6943379cb3411f3d2a79b3ab11559876c6ff25db04f41c5f6b6eeb574f6aa8152398584cc9fc00eb00f107a205bb1852e5ae1141ee48707076ad627c963f39
7
- data.tar.gz: 6c160c3026eac74b5fa1be6288409554a95cad8548b75e615015d99883774e87c3c61d8087588fb5d4e9840b2acd141b90a03e82cf21440ccaf0b221d8b0238e
6
+ metadata.gz: 5f6b26a244628091a4385883b04d588d682f1da0144dd56a827e74cceb5d61df5bdeeb8eb72e041c9203995b25f1b62605fde0d5d4eadc611b3ef7a02dd8df54
7
+ data.tar.gz: bf8a7eaae4377b4a52f4200057f9dd4e8e8273fdee243f258cf1e65a63f935873d11a9686e73e1e353b54c5a05458781a6811c991f76650d1810da6dfa2b5e0a
data/README.md CHANGED
@@ -170,6 +170,34 @@ If this config is set to true, Turbo::StreamsChannel is installed and a current
170
170
 
171
171
  If an `if_success_redirect_to` argument is provided and the save action was successful, `turbo_stream_save` would send the partials by channel.
172
172
 
173
+ **target-ID: Avoid the same definition in multiple places**
174
+
175
+ Without this gem a turbo action would be wrapped within two frames, for example:
176
+
177
+ ```haml
178
+ = turbo_stream.replace 'target-id' do
179
+ = render 'a partial'
180
+
181
+ ```
182
+
183
+ and within a partial:
184
+
185
+ ```haml
186
+ = turbo_frame_tag 'target-id' do
187
+ ... content
188
+ ```
189
+
190
+ The `turbo_frame_tag` would stay inside a partial in most cases. The reason is: On the first load, the target-id must be delivered up front, so that if the tag needs to be replaced later, turbo knows which part to replace.
191
+
192
+ This means that the target id must be defined in several places: inside a partial and at the place where the turbo action is defined.
193
+
194
+ In order to avoid this kind of tedious coding, the gem has a kind of fallback built in: If the argument `partial` is given, but the attribute `target_id` is not, the gem will get the target_id from the partial. The process is:
195
+
196
+ 1. Render the partial with the provided locals
197
+ 2. Grabs into the partial by Nokogiri and looks for a turbo_frame_tag and fetches the target_id.
198
+ 3. If all that not is found it raises a exception
199
+ 4. wraps the partial within the `turbo_stream.*` and sends this to the front.
200
+
173
201
  # Request Testing
174
202
 
175
203
  To test if the whole system works together, including javascript actions, so that finally a part reaches the surface, there is **Capybara** system testing. But it is a good practice to **break tests into smaller pieces**. So, there are helpers for **enabling the much faster request tests that are much easier to maintain**.
@@ -0,0 +1,4 @@
1
+ module RenderTurboStream
2
+ class RenderController < ActionController::Base
3
+ end
4
+ end
@@ -14,22 +14,28 @@
14
14
  <% else %>
15
15
  <% ctl = { partial: args[:partial], target_id: args[:target_id], action: args[:action] } %>
16
16
 
17
+
18
+
19
+ <% rendered_html = render(partial: args[:partial], locals: args[:locals]&.symbolize_keys, formats: [:html]) %>
20
+ <% unless args[:target].present? %>
21
+ <% args[:target] = RenderTurboStream::Libs.fetch_arguments_from_rendered_string(rendered_html)[:target] %>
22
+ <% unless args[:target].present? %>
23
+ <% raise 'No target specified by arguments and no target found inside the rendered partial' %>
24
+ <% end %>
25
+ <% end %>
26
+
27
+
17
28
  <% target_id = RenderTurboStream::Libs.target_to_target_id(args[:target]) %>
18
29
 
19
30
  <% info = { target_id: args[:target_id], partial: args[:partial], locals: args[:locals] } %>
20
31
 
21
32
 
22
-
23
33
  <% if args[:action].present? %>
24
34
  <% Rails.logger.debug(" • render-turbo-stream #{args[:action].upcase} => #{info}") %>
25
35
  <%= turbo_stream.send args[:action].to_sym, target_id do %>
26
- <% if RenderTurboStream::CheckTemplate.new(partial: args[:partial], action: args[:action]).add_turbo_frame_tag? %>
27
- <%= turbo_frame_tag RenderTurboStream::Libs.target_to_target_id(args[:target]) do %>
28
- <%= render args[:partial], locals: args[:locals]&.symbolize_keys %>
29
- <% end %>
30
- <% else %>
31
- <%= render args[:partial], locals: args[:locals]&.symbolize_keys %>
32
- <% end %>
36
+
37
+ <%= rendered_html %>
38
+
33
39
  <% end %>
34
40
 
35
41
  <% else %>
@@ -10,15 +10,20 @@
10
10
  <% rendered_partials.push(h) %>
11
11
  <% else %>
12
12
 
13
- <% wrap = RenderTurboStream::CheckTemplate.new(partial: s[:partial], action: s[:action]).add_turbo_frame_tag? %>
14
13
 
15
- <% if wrap %>
16
- <% html = turbo_frame_tag RenderTurboStream::Libs.target_to_target_id(s[:target]) do %>
17
- <%= (render s[:partial], locals: s[:locals]&.symbolize_keys, formats: [:html]) %>
18
- <% end %>
19
- <% else %>
20
14
  <% html = (render s[:partial], locals: s[:locals]&.symbolize_keys, formats: [:html]) %>
15
+
16
+
17
+
18
+ <% unless s[:target].present? %>
19
+ <% s[:target] = RenderTurboStream::Libs.fetch_arguments_from_rendered_string(html)[:target] %>
20
+ <% unless s[:target].present? %>
21
+ <% raise 'No target specified by arguments and no target found inside the rendered partial' %>
22
+ <% end %>
21
23
  <% end %>
24
+
25
+
26
+
22
27
  <% s[:target] = s[:target] %>
23
28
  <% s.delete(:id) %>
24
29
  <% rendered_partials.push({ html_response: html, type: 'stream-partial' }.merge(s)) %>
@@ -7,9 +7,10 @@ module RenderTurboStream
7
7
 
8
8
  def render_to_channel(channel, target, action, controller_self, partial: nil, template: nil, locals: nil)
9
9
 
10
+ _locals = (locals ? locals : {})
11
+
10
12
  # instance variables
11
13
 
12
- target_id = RenderTurboStream::Libs.target_to_target_id(target)
13
14
  check_template = RenderTurboStream::CheckTemplate.new(
14
15
  partial: partial,
15
16
  template: template,
@@ -19,35 +20,40 @@ module RenderTurboStream
19
20
 
20
21
  # add instance_variables to locals
21
22
 
22
- locals = {} unless locals # prevent error missing keys for nil
23
- if check_template.add_turbo_frame_tag?
24
- _layout = 'layouts/add_turbo_frame_tag'
25
- _locals = locals.merge(
26
- {
27
- render_turbo_stream_partial: partial,
28
- render_turbo_stream_target_id: target_id
29
- }
30
- )
31
- else
32
- _locals = locals
33
- _layout = false
34
- end
35
23
  check_template.templates_instance_variables.each do |v|
36
24
  _locals[:"render_turbo_stream_instance_variable_#{v}"] = controller_self.instance_variable_get(v.to_s)
37
25
  end
38
26
 
27
+ # fetch target-id
28
+
29
+ target_id = RenderTurboStream::Libs.target_to_target_id(target)
30
+ if !target.present? || Rails.env.test?
31
+ if partial.present?
32
+ rendered_html = RenderController.render(partial: partial, locals: _locals, layout: false)
33
+ elsif template.present?
34
+ rendered_html = RenderController.render(template: template, locals: _locals, layout: false)
35
+ end
36
+ if !target.present?
37
+ r = RenderTurboStream::Libs.fetch_arguments_from_rendered_string(rendered_html)
38
+ target_id = r[:target_id]
39
+ target = r[:target]
40
+ end
41
+ end
42
+
43
+ unless target.present? && target_id.present?
44
+ raise 'No target specified by arguments and no target found inside the rendered partial'
45
+ end
46
+
39
47
  # add headers for test
40
48
 
41
49
  if Rails.env.test?
42
- html = RenderTurboStreamRenderController.render(partial: partial, locals: _locals, layout: _layout) if partial
43
- html = RenderTurboStreamRenderController.render(template: template, locals: _locals, layout: _layout) if template
44
50
  props = {
45
51
  target: target,
46
52
  action: action,
47
53
  type: 'channel-partial',
48
54
  locals: locals,
49
55
  channel: channel,
50
- html_response: html.to_s
56
+ html_response: rendered_html.to_s
51
57
  }
52
58
 
53
59
  props[:partial] = partial if partial
@@ -66,23 +72,23 @@ module RenderTurboStream
66
72
 
67
73
  # send
68
74
 
69
- if partial
75
+ if partial.present?
70
76
  Turbo::StreamsChannel.send(
71
77
  "broadcast_#{action}_to",
72
78
  channel.to_s,
73
79
  target: target_id,
74
80
  partial: partial,
75
81
  locals: _locals&.symbolize_keys,
76
- layout: _layout
82
+ layout: false
77
83
  )
78
- elsif template
84
+ elsif template.present?
79
85
  Turbo::StreamsChannel.send(
80
86
  "broadcast_#{action}_to",
81
87
  channel.to_s,
82
88
  target: target_id,
83
89
  template: template,
84
- locals: locals&.symbolize_keys,
85
- layout: _layout
90
+ locals: _locals&.symbolize_keys,
91
+ layout: false
86
92
  )
87
93
  end
88
94
  end
@@ -114,7 +120,7 @@ module RenderTurboStream
114
120
  end
115
121
  end
116
122
 
117
- content = RenderTurboStreamRenderController.render(template: 'render_turbo_stream_command', layout: false, locals: { command: command, arguments: arguments })
123
+ content = RenderController.render(template: 'render_turbo_stream_command', layout: false, locals: { command: command, arguments: arguments })
118
124
 
119
125
  Turbo::StreamsChannel.broadcast_stream_to(
120
126
  channel,
@@ -23,12 +23,12 @@ module RenderTurboStream
23
23
  if $render_turbo_stream_check_templates[@key]
24
24
  @result = $render_turbo_stream_check_templates[@key]
25
25
  else
26
- @result = { instance_variables: [], add_turbo_frame_tag: false }
26
+ @result = { instance_variables: [] }
27
27
  fetch_nested_partials(1, partial: @partial_path, template: @template_path)
28
28
  $render_turbo_stream_check_templates[@key] ||= @result
29
29
  end
30
30
  else
31
- @result = { instance_variables: [], add_turbo_frame_tag: false }
31
+ @result = { instance_variables: [] }
32
32
  fetch_nested_partials(1, partial: @partial_path, template: @template_path)
33
33
  end
34
34
  end
@@ -37,10 +37,6 @@ module RenderTurboStream
37
37
  @result[:instance_variables]
38
38
  end
39
39
 
40
- def add_turbo_frame_tag?
41
- @result[:add_turbo_frame_tag]
42
- end
43
-
44
40
  private
45
41
 
46
42
  def production?
@@ -67,13 +63,6 @@ module RenderTurboStream
67
63
  end
68
64
  end
69
65
 
70
- conf = Rails.configuration.x.render_turbo_stream.auto_wrap_for_actions
71
- if stack_level == 1 && conf.present? && conf.include?(@action.to_sym)
72
- unless _code.match(/(turbo_frame_tag|turbo-frame)/)
73
- @result[:add_turbo_frame_tag] = true
74
- end
75
- end
76
-
77
66
  loop do
78
67
  _matched_partial = _code.match((/\brender[ ](partial:|())(|[ ])("|')[a-z_\/]+("|')/))
79
68
  _code = _code[(_code.index(_matched_partial.to_s) + 5)..-1]
@@ -1,7 +1,7 @@
1
1
  module RenderTurboStream
2
2
  module ControllerChannelHelpers
3
3
 
4
- def render_to_all(target_id, action = :replace, partial: nil, template: nil, locals: nil)
4
+ def render_to_all(target_id = nil, action = :replace, partial: nil, template: nil, locals: nil)
5
5
  evaluate_instance_variables
6
6
  render_to_channel(
7
7
  'all',
@@ -13,7 +13,7 @@ module RenderTurboStream
13
13
  )
14
14
  end
15
15
 
16
- def render_to_me(target_id, action = :replace, partial: nil, locals: nil)
16
+ def render_to_me(target_id = nil, action = :replace, partial: nil, locals: nil)
17
17
  begin
18
18
  u_id = helpers.current_user&.id
19
19
  unless u_id.present?
@@ -34,7 +34,7 @@ module RenderTurboStream
34
34
  )
35
35
  end
36
36
 
37
- def render_to_authenticated_group(group, target_id, action = :replace, partial: nil, locals: nil)
37
+ def render_to_authenticated_group(group, target_id = nil, action = :replace, partial: nil, locals: nil)
38
38
  begin
39
39
  u_id = helpers.current_user&.id
40
40
  unless u_id.present?
@@ -55,7 +55,7 @@ module RenderTurboStream
55
55
  )
56
56
  end
57
57
 
58
- def render_to_channel(channel, target_id, action, partial: nil, template: nil, locals: nil, instance_variables: true)
58
+ def render_to_channel(channel, target_id = nil, action = :replace, partial: nil, template: nil, locals: nil, instance_variables: true)
59
59
 
60
60
  raise 'Arguments partial and template cannot both be specified' if partial && template
61
61
 
@@ -21,7 +21,7 @@ module RenderTurboStream
21
21
  if_error_add: nil, # additional partials that should be rendered if save_action failed
22
22
  add: [], # additional streams
23
23
 
24
- if_success_notices: nil, # array of strings, override default generated flash generation in the case of success
24
+ if_success_notices: nil, # array of strings, or string, override default generated flash generation in the case of success
25
25
  if_error_alerts: nil,
26
26
  add_notices: nil, # array of strings
27
27
  add_alerts: nil,
@@ -132,11 +132,11 @@ module RenderTurboStream
132
132
  else
133
133
  r[:target] = props[:target]
134
134
  end
135
- raise "Missing attribute :target in #{props}" if !props[:target].present?
136
135
  r.delete(:target_id)
137
136
  r[:action] = (props[:action].present? ? props[:action] : :replace)
138
137
  r[:partial] = RenderTurboStream::Libs.partial_path(props[:target], props[:target_id], controller_path, props[:partial])
139
138
  r[:type] = 'stream-partial'
139
+
140
140
  ary.push(r)
141
141
  elsif pr.is_a?(Array)
142
142
  raise "array has to contain at least one element: #{pr}" unless pr.first.present?
@@ -157,7 +157,7 @@ module RenderTurboStream
157
157
 
158
158
  # renders a partial to turbo_stream
159
159
 
160
- def stream_partial(target_id, partial: nil, action: :replace, locals: {})
160
+ def stream_partial(target_id = nil, partial: nil, action: :replace, locals: {})
161
161
  render_turbo_stream(
162
162
  [
163
163
  {
@@ -5,7 +5,7 @@ module RenderTurboStream
5
5
  @save_action = save_action
6
6
  end
7
7
 
8
- def generate_flash( model_name, controller_action, if_success_notices, if_error_alerts, add_notices, add_alerts )
8
+ def generate_flash(model_name, controller_action, if_success_notices, if_error_alerts, add_notices, add_alerts)
9
9
 
10
10
  target_id = (Rails.configuration.x.render_turbo_stream.flash_target_id rescue nil)
11
11
  raise "Missing configuration: config.x.render_turbo_stream.flash_target_id" unless target_id
@@ -14,26 +14,33 @@ module RenderTurboStream
14
14
  turbo_action = Rails.configuration.x.render_turbo_stream.flash_turbo_action
15
15
  raise "Missing configuration: configuration.x.render_turbo_stream.flash_turbo_action" unless turbo_action
16
16
 
17
-
18
17
  if @save_action
19
18
  notices = if if_success_notices
20
- if_success_notices
21
- else
22
- str = I18n.t(
23
- "activerecord.render_turbo_stream_success.#{controller_action}"
24
- )
25
- [format(str, model_name: model_name)]
26
- end
19
+ if if_success_notices.is_a?(String)
20
+ [if_success_notices]
21
+ else
22
+ if_success_notices
23
+ end
24
+ else
25
+ str = I18n.t(
26
+ "activerecord.render_turbo_stream_success.#{controller_action}"
27
+ )
28
+ [format(str, model_name: model_name)]
29
+ end
27
30
  alerts = []
28
31
  else
29
32
  alerts = if if_error_alerts
30
- if_error_alerts
31
- else
32
- str = I18n.t(
33
- "activerecord.render_turbo_stream_errors.#{controller_action}"
34
- )
35
- [format(str, model_name: model_name)]
36
- end
33
+ if if_error_alerts.is_a?(String)
34
+ [if_error_alerts]
35
+ else
36
+ if_error_alerts
37
+ end
38
+ else
39
+ str = I18n.t(
40
+ "activerecord.render_turbo_stream_errors.#{controller_action}"
41
+ )
42
+ [format(str, model_name: model_name)]
43
+ end
37
44
  notices = []
38
45
  end
39
46
 
@@ -63,13 +70,13 @@ module RenderTurboStream
63
70
  { turbo_actions: turbo_actions, alerts: alerts, notices: notices }
64
71
  end
65
72
 
66
- def additional_actions( if_success_add, if_error_add, add )
73
+ def additional_actions(if_success_add, if_error_add, add)
67
74
 
68
75
  (@save_action ? make_actions(if_success_add) : make_actions(if_error_add)) + make_actions(add)
69
76
 
70
77
  end
71
78
 
72
- def generate_action( controller_path, target_id, action, partial, locals )
79
+ def generate_action(controller_path, target_id, action, partial, locals)
73
80
  libs = RenderTurboStream::Libs
74
81
  target = libs.target_id_to_target(target_id)
75
82
  _partial = libs.partial_path(nil, target_id, controller_path, partial)
@@ -29,5 +29,18 @@ module RenderTurboStream
29
29
  end
30
30
  end
31
31
 
32
+ def self.fetch_arguments_from_rendered_string(rendered_string)
33
+ noko = Nokogiri::HTML(rendered_string)
34
+ frame = noko.at_css('turbo-frame')
35
+ if frame.present?
36
+ {
37
+ target_id: frame[:id],
38
+ target: target_id_to_target(frame[:id])
39
+ }
40
+ else
41
+ {}
42
+ end
43
+ end
44
+
32
45
  end
33
46
  end
@@ -1,3 +1,3 @@
1
1
  module RenderTurboStream
2
- VERSION = "4.1.6"
2
+ VERSION = "4.2.0"
3
3
  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: 4.1.6
4
+ version: 4.2.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-05-17 00:00:00.000000000 Z
11
+ date: 2023-05-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -27,10 +27,10 @@ dependencies:
27
27
  description: 'A set of helpers that allow a UNIFIED WORKFLOW for TurboStream and TurboStreams::Channel.
28
28
  To avoid a heavy mix of view and logic, partials and templates can be rendered directly
29
29
  from the controller. There is no need to write *.turbo_stream.* templates anymore.
30
- Logic can stay on the Ruby side, in the controller. Javascript actions can also
31
- be executed directly from the controller. TESTING: To reduce the amount of hard-to-maintain
32
- system tests, this gem allows detailed request tests. A DEMO PROJECT with all this
33
- built in, along with system and request tests, is linked in the README.'
30
+ Logic can stay on in the controller. Javascript actions can also be executed directly
31
+ from the controller. TESTING: To reduce the amount of hard-to-maintain system tests,
32
+ this gem allows detailed request tests. A DEMO PROJECT with all this built in, along
33
+ with system and request tests, is linked in the README.'
34
34
  email:
35
35
  - christian@sedlmair.ch
36
36
  executables: []
@@ -40,7 +40,7 @@ files:
40
40
  - README.md
41
41
  - Rakefile
42
42
  - app/controllers/render_turbo_stream/application_controller.rb
43
- - app/controllers/render_turbo_stream/render_turbo_stream_render_controller.rb
43
+ - app/controllers/render_turbo_stream/render_controller.rb
44
44
  - app/views/layouts/_add_turbo_frame_tag.html.erb
45
45
  - app/views/render_turbo_stream.turbo_stream.erb
46
46
  - app/views/render_turbo_stream_command.html.erb
@@ -86,5 +86,5 @@ requirements: []
86
86
  rubygems_version: 3.4.12
87
87
  signing_key:
88
88
  specification_version: 4
89
- summary: Complete workflow for turbo-rails with a testing strategy.
89
+ summary: Makes working with Turbo fun and ensures quality.
90
90
  test_files: []
@@ -1,4 +0,0 @@
1
- module RenderTurboStream
2
- class RenderTurboStreamRenderController < ActionController::Base
3
- end
4
- end