render_turbo_stream 1.4.14 → 2.0.0

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: c2c84aacdaefecd60e436ebd13e68801e87d02d3318ded429a643605b2ec94a3
4
- data.tar.gz: 1b6089600ec4abe349d2cae88a1802f258a535e2303f9289cc29ec0e7c09bf66
3
+ metadata.gz: f1923db5dbed0c8a3f0cc583ba8de9469b16f0d09fdf3d46b48002ee1099537a
4
+ data.tar.gz: 7c2bdf446e15de06c2704311fc2725b84613592ac91827eaa4df69a51d383d1a
5
5
  SHA512:
6
- metadata.gz: 83b71f6a084d9da96a09d710bc64c46506a424a8d704838ed0b91b54853cf799d3c1c336c2059bfd23f8ec70581f850c87341bbc03419efe2627c762fee94ff3
7
- data.tar.gz: a623f4b6acf363a224adfbf4e4e246bec3fcd3f3cc267452ee66bb8bdd6067d0c50a94de45611edbd1640ab25c567d05a9a4853d24d2fbe885a8e2427c336454
6
+ metadata.gz: f2258c4ae8b77734f82837a883011591a5d6798d1110f3b63cf7ea557a3a3c60e8f5a358dd9a3dc963c02e0215979d91842d25dd94dfaf6c79e8cc3cc4483e59
7
+ data.tar.gz: 1495b280772066632effbc8bf484c9d5aa867e3c8fe86d745b6264fb1e0b029420be850bfe432765ade82bc0d5617fcb1dcce2ca2a5611e4c8e01b150483f5bb
data/README.md CHANGED
@@ -2,17 +2,21 @@
2
2
 
3
3
  Defining templates like `(create|update).turbo_stream.haml` annoyed me.
4
4
 
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.
5
+ The biggest advantage of this gem is the testing strategy.
6
+
7
+ 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. Includes helpers for enabling request tests.
6
8
 
7
9
  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
10
 
9
11
  ATTENTION: This plugin is in a early state.
10
12
 
11
- Hope this gem can help you.
12
-
13
13
  An overview of how we design a rails-7 application with turbo
14
14
  is [published on dev.to](https://dev.to/chmich/rails-7-vite-wrapping-up-1pia).
15
15
 
16
+ A quick and dirty application with all the features, including tests, built in is [here](https://gitlab.com/sedl/renderturbostream_railsapp).
17
+
18
+ Hope it can help you.
19
+
16
20
  ## Installation
17
21
 
18
22
  ```ruby
@@ -71,6 +75,9 @@ To get redirection and many other options working, you need to follow the instal
71
75
 
72
76
  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).
73
77
 
78
+ **Turbo::StreamsChannel**
79
+
80
+ The Rails team has seamlessly integrated `ActionCable` as `Turbo::StreamsChannel` into `Turbo Rails`. For installation along with this gem, see the [README](https://gitlab.com/sedl/renderturbostream/-/blob/main/README-cable.md).
74
81
  ## Usage
75
82
 
76
83
  `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:
@@ -140,11 +147,19 @@ render_turbo_stream(
140
147
 
141
148
  Under the hood, inside a `*.turbo_stream.erb` template, it does the following: `= turbo_stream.send args.first, *(args[1..-1])`
142
149
 
143
- **WORKAROUND for redirects inside frame**
150
+ **WORKAROUNDS for redirects inside frame**
144
151
 
145
152
  Suppose you have a CRUD controller that should do all its actions inside a turbo frame. Classic redirect_to, together with a turbo_stream action on the same response, would raise «Render and/or redirect were called multiple times in this action». See [issue](https://gitlab.com/sedl/renderturbostream/-/issues/3).
146
153
 
147
- A workaround is to use the src attribute of the parent frame. `turbo_frame_set_src` comes from turbo_power. The code could look like this:
154
+ There are two workarounds:
155
+
156
+ ```ruby
157
+ config.x.render_turbo_stream.use_cable_for_turbo_stream_save = true
158
+ ```
159
+
160
+ With this config, the `turbo_stream_save` method will send flash messages through `Turbo::StreamsChannel` (if installed as described above) to a channel to the currently logged in user in parallel with the redirect.
161
+
162
+ Another workaround is to use the src attribute of the parent frame. `turbo_frame_set_src` comes from turbo_power. The code might look like this:
148
163
 
149
164
  ```ruby
150
165
  def update
@@ -155,9 +170,6 @@ def update
155
170
  :turbo_frame_set_src,
156
171
  'cars-box',
157
172
  cars_path
158
- ],
159
- [
160
- #... more actions possible ...
161
173
  ]
162
174
  ]
163
175
  )
@@ -1,22 +1,62 @@
1
1
  module RenderTurboStream
2
- module TurboCableHelpers
2
+ module TurboCableHelpers
3
3
 
4
+ def cable_to_all_authenticated_users
5
+ if user_signed_in?
4
6
 
5
- def turbo_cable_to_authenticated
7
+ end
8
+ end
6
9
 
10
+ def cable_to_me(id, action, *args, partial: nil, locals: nil)
11
+ begin
12
+ u_id = helpers.current_user&.id
13
+ a=1
14
+ unless u_id.present?
15
+ Rails.logger.debug(' • SKIP RenderTurboStream.cable_to_me because current_user is nil')
16
+ return
7
17
  end
8
-
9
- def turbo_cable_to_current_user(target, action, *args, partial: nil, locals: nil)
10
- if [:append, :prepend, :replace].include?(action.to_sym)
11
- Turbo::StreamsChannel.send("broadcast_#{action}_to", "current_user_#{helpers.current_user.id}", *args, target: target, partial: partial, locals: locals)
12
- else
13
- # Turbo::StreamsChannel.broadcast_action_to(
14
- # "current_user_#{helpers.current_user.id}",
15
- # action:'toggle_css_class',
16
- # 'colored-element'
17
- # )
18
+ rescue
19
+ Rails.logger.debug(' • ERROR RenderTurboStream.cable_to_me because current_user is not available')
20
+ return
21
+ end
22
+ if Rails.env.test?
23
+ args = {
24
+ target: "##{id}",
25
+ action: action,
26
+ type: 'cable-partial',
27
+ args: args,
28
+ partial: partial,
29
+ locals: locals
30
+ }
31
+ h = response.headers.to_h
32
+ i = 1
33
+ loop do
34
+ k = "test-turbo-cable-#{i}"
35
+ unless h.keys.include?(k)
36
+ response.headers[k] = args.to_json
37
+ break
18
38
  end
39
+ i += 1
19
40
  end
20
-
41
+ end
42
+ if [:append, :prepend, :replace].include?(action.to_sym)
43
+ Turbo::StreamsChannel.send(
44
+ "broadcast_#{action}_to",
45
+ "current_user_#{helpers.current_user.id}",
46
+ *args,
47
+ target: id,
48
+ partial: partial,
49
+ locals: locals&.symbolize_keys,
50
+ layout: false
51
+ )
52
+ else
53
+ # Turbo::StreamsChannel.broadcast_action_to(
54
+ # "current_user_#{helpers.current_user.id}",
55
+ # action:'toggle_css_class',
56
+ # 'colored-element'
57
+ # )
58
+ end
21
59
  end
60
+
61
+ end
22
62
  end
@@ -1,15 +1,27 @@
1
1
  module RenderTurboStream
2
2
  module TurboCableViewHelpers
3
3
 
4
- def turbo_cable_from_current_user
4
+ def cable_from_me
5
5
  if current_user
6
6
  turbo_stream_from "current_user_#{current_user.id}"
7
+ else
8
+ Rails.logger.debug(" • SKIP CABLE_FROM_ME because not authenticated")
7
9
  end
8
10
  end
9
11
 
10
- def turbo_cable_from_authenticated_users
12
+ def cable_from_all_authenticated_users
11
13
  if user_signed_in?
12
- turbo_stream_from "authenticated_users"
14
+ turbo_stream_from "all_authenticated_users"
15
+ else
16
+ Rails.logger.debug(" • SKIP CABLE_FROM_ALL_AUTHENTICATED_USERS because not authenticated")
17
+ end
18
+ end
19
+
20
+ def local_model(object)
21
+ if (object.is_a?(String) && object[0..5] == 'gid://') || object.is_a?(GlobalID)
22
+ GlobalID::Locator.locate(object)
23
+ else
24
+ object
13
25
  end
14
26
  end
15
27
 
@@ -1,3 +1,3 @@
1
1
  module RenderTurboStream
2
- VERSION = "1.4.14"
2
+ VERSION = "2.0.0"
3
3
  end
@@ -16,6 +16,7 @@ module RenderTurboStream
16
16
  id: nil, # if nil: no partial is rendered
17
17
  partial: nil, # example: 'customers/form' default: "#{controller_path}/#{id}"
18
18
  action: 'replace', # options: append, prepend
19
+ flash_action: action_name, # options: 'update', 'create', otherwise you have to declare a translation in config/locales like "activerecord.success.#{flash_action}" and "activerecord.errors.#{flash_action}"
19
20
  locals: {}, # locals used by the partial
20
21
  streams_on_success: [
21
22
  {
@@ -67,35 +68,47 @@ module RenderTurboStream
67
68
  if save_action
68
69
  flash_notices = if flashes_on_success.present?
69
70
  flashes_on_success
70
- elsif action_name == 'create'
71
+ elsif flash_action.to_s == 'create'
71
72
  str = I18n.t(
72
73
  'activerecord.success.successfully_created',
73
74
  default: '%<model_name>s successfully created'
74
75
  )
75
76
  [format(str, model_name: model_name)]
76
- elsif action_name == 'update'
77
+ elsif flash_action.to_s == 'update'
77
78
  str = I18n.t(
78
79
  'activerecord.success.successfully_updated',
79
80
  default: '%<model_name>s successfully updated'
80
81
  )
81
82
  [format(str, model_name: model_name)]
83
+ else
84
+ str = I18n.t(
85
+ "activerecord.success.#{flash_action}",
86
+ default: '%<model_name>s successfully updated'
87
+ )
88
+ [format(str, model_name: model_name)]
82
89
  end
83
90
  flash_alerts = []
84
91
  else
85
92
  flash_alerts = if flashes_on_error.present?
86
93
  flashes_on_error
87
- elsif action_name == 'create'
94
+ elsif flash_action.to_s == 'create'
88
95
  str = I18n.t(
89
96
  'activerecord.errors.messages.could_not_create',
90
97
  default: '%<model_name>s could not be created'
91
98
  )
92
99
  [format(str, model_name: model_name)]
93
- elsif action_name == 'update'
100
+ elsif flash_action.to_s == 'update'
94
101
  str = I18n.t(
95
102
  'activerecord.errors.messages.could_not_update',
96
103
  default: '%<model_name>s could not be updated'
97
104
  )
98
105
  [format(str, model_name: model_name)]
106
+ else
107
+ str = I18n.t(
108
+ "activerecord.errors.messages.#{flash_action}",
109
+ default: '%<model_name>s could not be updated'
110
+ )
111
+ [format(str, model_name: model_name)]
99
112
  end
100
113
  flash_notices = []
101
114
  end
@@ -145,10 +158,24 @@ module RenderTurboStream
145
158
  ])
146
159
  elsif save_action && redirect_on_success_to.present?
147
160
  response.status = 302
148
- flash[:alert] = flash_alerts
149
- flash[:notice] = flash_notices
150
- Rails.logger.debug(" • Set flash[:alert] => #{flash_alerts}") if flash_alerts.present?
151
- Rails.logger.debug(" • Set flash[:notice] => #{flash_notices}") if flash_notices.present?
161
+ if Rails.configuration.x.render_turbo_stream.use_cable_for_turbo_stream_save && helpers.user_signed_in?
162
+ streams.each do |s|
163
+ next unless s.is_a?(Hash)
164
+ Rails.logger.debug(" • Send by Cable => «#{s}»")
165
+ cable_to_me(
166
+ s[:id],
167
+ :prepend,
168
+ partial: s[:partial],
169
+ locals: s[:locals]
170
+ )
171
+ end
172
+
173
+ else
174
+ flash[:alert] = flash_alerts
175
+ flash[:notice] = flash_notices
176
+ Rails.logger.debug(" • Set flash[:alert] => #{flash_alerts}") if flash_alerts.present?
177
+ Rails.logger.debug(" • Set flash[:notice] => #{flash_notices}") if flash_notices.present?
178
+ end
152
179
  redirect_to redirect_on_success_to
153
180
 
154
181
  else
@@ -184,6 +211,7 @@ module RenderTurboStream
184
211
  if request.format.to_sym == :turbo_stream
185
212
  render template: 'render_turbo_stream', locals: { streams: ary }, layout: false, formats: :turbo_stream
186
213
  else
214
+ Rails.logger.debug(" • Render Turbo Stream RENDERING AS HTML because request.format => #{request.format}")
187
215
  render template: 'render_turbo_stream', locals: { streams: ary }, layout: false, formats: :html
188
216
  end
189
217
  end
@@ -209,7 +237,24 @@ module RenderTurboStream
209
237
  class Libs
210
238
  def self.all_responses(response)
211
239
  e = Nokogiri::HTML(response.body).search('#rendered-partials').first
212
- JSON.parse(e.inner_html)
240
+ if e.present?
241
+ res = JSON.parse(e.inner_html)
242
+ else
243
+ res = []
244
+ end
245
+ cables = response.headers.to_h.select { |k| k.match(/^test-turbo-cable-[\d]+$/) }
246
+ cables.each do |k, v|
247
+ args = JSON.parse(v)
248
+ html = ApplicationController.render(partial: args['partial'], locals: args['locals'].symbolize_keys)
249
+ res.push(
250
+ args.merge(
251
+ {
252
+ 'html_response' => html,
253
+ }
254
+ )
255
+ )
256
+ end
257
+ res
213
258
  end
214
259
 
215
260
  # if partial is one word, its checked against the last behind the slash, example: 'articles/form' matches 'form'
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.14
4
+ version: 2.0.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-29 00:00:00.000000000 Z
11
+ date: 2023-05-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails