render_turbo_stream 1.4.14 → 2.0.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: 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