render_turbo_stream 3.0.4 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,6 +2,7 @@ module RenderTurboStream
2
2
  module ControllerChannelHelpers
3
3
 
4
4
  def render_to_all(target_id, action = :replace, partial: nil, template: nil, locals: nil)
5
+ evaluate_instance_variables
5
6
  render_to_channel(
6
7
  'all',
7
8
  target_id,
@@ -26,7 +27,7 @@ module RenderTurboStream
26
27
 
27
28
  render_to_channel(
28
29
  "authenticated-user-#{helpers.current_user.id}",
29
- target_id,
30
+ RenderTurboStream::Libs.target_id_to_target(target_id),
30
31
  action,
31
32
  partial: partial,
32
33
  locals: locals
@@ -47,23 +48,25 @@ module RenderTurboStream
47
48
 
48
49
  render_to_channel(
49
50
  "authenticated-group-#{group}",
50
- target_id,
51
+ RenderTurboStream::Libs.target_id_to_target(target_id),
51
52
  action,
52
53
  partial: partial,
53
54
  locals: locals
54
55
  )
55
56
  end
56
57
 
57
- def render_to_channel(channel, target_id, action, partial: nil, template: nil, locals: nil)
58
+ def render_to_channel(channel, target_id, action, partial: nil, template: nil, locals: nil, instance_variables: true)
59
+
60
+ raise 'Arguments partial and template cannot both be specified' if partial && template
58
61
 
59
62
  disable_default = false
60
- if partial
61
- template = nil
62
- elsif template.present? && !template.to_s.include?('/')
63
- template = [controller_path, template].join('/')
63
+ if partial.present?
64
+ _partial = RenderTurboStream::Libs.partial_path(nil, target_id, controller_path, partial)
65
+ elsif template.present?
66
+ _template = RenderTurboStream::Libs.partial_path(nil, target_id, controller_path, template)
64
67
  disable_default = true
65
68
  else
66
- template = [controller_path, action_name].join('/')
69
+ _template = [controller_path, action_name].join('/')
67
70
  disable_default = true
68
71
  end
69
72
 
@@ -73,7 +76,17 @@ module RenderTurboStream
73
76
  @render_cable_template_was_called = true
74
77
  end
75
78
 
76
- RenderTurboStream::ChannelLibs.render_to_channel(response, channel, target_id, action, template: template, partial: partial, locals: locals)
79
+ evaluate_instance_variables
80
+
81
+ libs = RenderTurboStream::ChannelLibs.new(response)
82
+ libs.render_to_channel(
83
+ channel,
84
+ RenderTurboStream::Libs.target_id_to_target(target_id),
85
+ action,
86
+ self,
87
+ template: _template,
88
+ partial: _partial, locals: locals
89
+ )
77
90
 
78
91
  end
79
92
 
@@ -114,7 +127,86 @@ module RenderTurboStream
114
127
  end
115
128
 
116
129
  def action_to_channel(channel, command, arguments)
117
- RenderTurboStream::ChannelLibs.action_to_channel(response, channel, command, arguments)
130
+ libs = RenderTurboStream::ChannelLibs.new(response)
131
+ libs.action_to_channel(channel, command, arguments)
132
+ end
133
+
134
+ def turbo_channel_save(
135
+ save_action,
136
+ object: nil, # object used in save_action, example: @customer
137
+
138
+ if_success_redirect_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
139
+
140
+ if_success: nil, # hash for a partial to render or array with actions (as array) or hashes for partials within
141
+ if_error: nil, # additional partials that should be rendered if save_action failed
142
+ add: [], # additional streams
143
+
144
+ if_success_notices: nil, # array of strings, override default generated flash generation in the case of success
145
+ if_error_alerts: nil,
146
+ add_notices: nil, # array of strings
147
+ add_alerts: nil,
148
+
149
+ flash_controller_action_name: action_name, # options: 'update', 'create', otherwise you have to declare a translation in config/locales like "activerecord.success.#{flash_controller_action_name}" and "activerecord.errors.#{flash_controller_action_name}"
150
+ instance_variables: true # options: if false, nothing happens, if true: Instance variables that matching to controller name like @article or @articles are set to locals. By Array you can add more, example: [:my_var]
151
+ )
152
+
153
+ # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
154
+ # LOGIC
155
+ # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
156
+
157
+ unless object
158
+ object = eval("@#{controller_name.classify.underscore}")
159
+ end
160
+
161
+ libs = RenderTurboStream::ControllerLibs.new(save_action)
162
+ model_name = object.model_name.human
163
+
164
+ turbo_actions = libs.generate_flash(
165
+ model_name,
166
+ flash_controller_action_name,
167
+ if_success_notices,
168
+ if_error_alerts,
169
+ add_notices,
170
+ add_alerts,
171
+ )[:turbo_actions]
172
+
173
+ turbo_actions += libs.additional_actions(
174
+ if_success,
175
+ if_error,
176
+ add
177
+ )
178
+
179
+ if libs.action_errors(turbo_actions).present?
180
+ raise libs.action_errors(turbo_actions).join(', ')
181
+ end
182
+
183
+ # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
184
+ #== RENDER TO CHANNEL
185
+ # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
186
+
187
+ libs = RenderTurboStream::ChannelLibs.new(response)
188
+ if (helpers.current_user.id rescue false)
189
+ libs.send_actions_to_channel(
190
+ "authenticated-user-#{helpers.current_user.id}",
191
+ turbo_actions,
192
+ instance_variables: instance_variables
193
+ )
194
+ end
195
+
196
+ if save_action && if_success_redirect_to.present?
197
+ response.status = 302
198
+ redirect_to if_success_redirect_to
199
+ end
200
+
201
+ end
202
+
203
+ @render_turbo_stream_evaluate_instance_variables = nil
204
+
205
+ def evaluate_instance_variables
206
+ @render_turbo_stream_evaluate_instance_variables ||= (
207
+ { var_test: 'alpha' }
208
+ )
209
+
118
210
  end
119
211
 
120
212
  end
@@ -2,187 +2,118 @@ module RenderTurboStream
2
2
  module ControllerHelpers
3
3
 
4
4
  # Handles translated flash messages as defined in translations and configs.
5
- # If :redirect_on_success_to and channel set up and use_channel_for_turbo_stream_save are configured, sends flash message by channel_to_me.
5
+ # If :if_success_redirect_to and channel set up and allow_channel_to_me_for_turbo_stream_save are configured, sends flash message by channel_to_me.
6
6
  # you can add more stream actions to the same response
7
7
 
8
8
  def turbo_stream_save(
9
9
  save_action,
10
- 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
11
- turbo_redirect_on_success_to: nil, # does a full page redirect (break out of all frames by turbo_power redirect)
12
10
  object: nil, # object used in save_action, example: @customer
13
- id: nil, # if nil: no partial is rendered
14
- partial: nil, # example: 'customers/form' default: "#{controller_path}/#{id}"
11
+
12
+ if_success_redirect_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
13
+ if_success_turbo_redirect_to: nil, # does a full page redirect (break out of all frames by turbo_power redirect)
14
+
15
+ target_id: nil, # IF NIL: no partial will be rendered AND IF allowed by config: it would send by channel *_to_me and not affect the default response-rendering
16
+ partial: nil,
15
17
  action: 'replace', # options: append, prepend
16
- 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}"
17
- locals: {}, # locals used by the partial
18
- streams_on_success: [
19
- {
20
- id: nil,
21
- partial: 'form',
22
- locals: {},
23
- action: 'replace'
24
- }
25
- ], # additional partials that should be rendered if save_action succeeded
26
- streams_on_error: [
27
- {
28
- id: nil,
29
- partial: 'form',
30
- locals: {},
31
- action: 'replace'
32
- }
33
- ], # additional partials that should be rendered if save_action failed
34
- add_flash_alerts: [], #=> array of strings
35
- add_flash_notices: [], #=> array of strings
36
- flashes_on_success: [], #=> array of strings
37
- flashes_on_error: [] #=> array of strings
18
+ locals: {}, # locals used by the target_id
19
+
20
+ if_success: nil, # hash for a partial to render or array with actions (as array) or hashes for partials within
21
+ if_error: nil, # additional partials that should be rendered if save_action failed
22
+ add: [], # additional streams
23
+
24
+ if_success_notices: nil, # array of strings, override default generated flash generation in the case of success
25
+ if_error_alerts: nil,
26
+ add_notices: nil, # array of strings
27
+ add_alerts: nil,
28
+
29
+ flash_controller_action_name: action_name # options: 'update', 'create', otherwise you have to declare a translation in config/locales like "activerecord.success.#{flash_controller_action_name}" and "activerecord.errors.#{flash_controller_action_name}"
38
30
  )
39
31
 
32
+ # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
33
+ # EXCEPTIONS
34
+ # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
35
+
36
+ raise 'render_turbo_stream: arguments target_id and if_success_redirect_to cannot be provided both' if target_id && if_success_redirect_to
37
+
38
+ # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
39
+ # LOGIC
40
+ # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
41
+
40
42
  unless object
41
43
  object = eval("@#{controller_name.classify.underscore}")
42
44
  end
43
45
 
44
- #== Streams / Partials
46
+ libs = RenderTurboStream::ControllerLibs.new(save_action)
47
+ model_name = object.model_name.human
45
48
 
46
- streams = (id ? [id: id, partial: partial, locals: locals, action: action] : [])
49
+ streams = (target_id ? libs.generate_action(controller_path, target_id, action, partial, locals) : [])
50
+
51
+ flashes = libs.generate_flash(
52
+ model_name,
53
+ flash_controller_action_name,
54
+ if_success_notices,
55
+ if_error_alerts,
56
+ add_notices,
57
+ add_alerts,
58
+ )
59
+ streams += flashes[:turbo_actions]
60
+
61
+ streams += libs.additional_actions(
62
+ if_success,
63
+ if_error,
64
+ add
65
+ )
47
66
 
48
- if save_action
49
- response.status = 200
50
- streams_on_success.each do |s|
51
- if s.is_a?(Array)
52
- streams.push(s)
53
- elsif s.is_a?(Hash) && s[:id].present?
54
- streams.push(s)
55
- end
56
- end
57
- else
58
- response.status = :unprocessable_entity
59
- streams += streams_on_error.select { |s| s[:id].present? }
67
+ if libs.action_errors(streams).present?
68
+ raise libs.action_errors(streams).join(', ')
60
69
  end
61
70
 
62
- #== FLASHES
63
-
64
- model_name = object.model_name.human
65
- if save_action
66
- flash_notices = if flashes_on_success.present?
67
- flashes_on_success
68
- elsif flash_action.to_s == 'create'
69
- str = I18n.t(
70
- 'activerecord.success.successfully_created',
71
- default: '%<model_name>s successfully created'
72
- )
73
- [format(str, model_name: model_name)]
74
- elsif flash_action.to_s == 'update'
75
- str = I18n.t(
76
- 'activerecord.success.successfully_updated',
77
- default: '%<model_name>s successfully updated'
78
- )
79
- [format(str, model_name: model_name)]
80
- else
81
- str = I18n.t(
82
- "activerecord.success.#{flash_action}",
83
- default: '%<model_name>s successfully updated'
84
- )
85
- [format(str, model_name: model_name)]
86
- end
87
- flash_alerts = []
88
- else
89
- flash_alerts = if flashes_on_error.present?
90
- flashes_on_error
91
- elsif flash_action.to_s == 'create'
92
- str = I18n.t(
93
- 'activerecord.errors.messages.could_not_create',
94
- default: '%<model_name>s could not be created'
95
- )
96
- [format(str, model_name: model_name)]
97
- elsif flash_action.to_s == 'update'
98
- str = I18n.t(
99
- 'activerecord.errors.messages.could_not_update',
100
- default: '%<model_name>s could not be updated'
101
- )
102
- [format(str, model_name: model_name)]
103
- else
104
- str = I18n.t(
105
- "activerecord.errors.messages.#{flash_action}",
106
- default: '%<model_name>s could not be updated'
107
- )
108
- [format(str, model_name: model_name)]
109
- end
110
- flash_notices = []
71
+ unless save_action
72
+ response.status = 422
111
73
  end
112
74
 
113
- flash_notices += add_flash_notices.to_a
114
- flash_alerts += add_flash_alerts.to_a
115
- _flash_id = Rails.configuration.x.render_turbo_stream.flash_id
116
- flash_id = (_flash_id ? _flash_id : "ERROR, MISSING CONFIG => config.x.render_turbo_stream.flash_id")
117
- flash_partial = Rails.configuration.x.render_turbo_stream.flash_partial
118
- flash_action = Rails.configuration.x.render_turbo_stream.flash_action
119
- flash_notices.each do |notice|
120
- next unless notice.present?
121
- # inside the flash partial has to be a loop that handles all theese flashes
122
- flash_stream = {
123
- id: flash_id,
124
- partial: flash_partial,
125
- action: flash_action,
126
- locals: { success: true, message: notice }
127
- }
128
- streams.push(flash_stream)
129
- end
130
- flash_alerts.each do |alert|
131
- next unless alert.present?
132
- # inside the flash partial has to be a loop that handles all theese flashes
133
- flash_stream = {
134
- id: flash_id,
135
- partial: flash_partial,
136
- action: flash_action,
137
- locals: { success: false, message: alert }
138
- }
139
- streams.push(flash_stream)
140
- end
75
+ # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
76
+ #== RENDER TO STREAM
77
+ # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
141
78
 
142
- #== render
79
+ allow_channel = (Rails.configuration.x.render_turbo_stream.allow_channel_to_me_for_turbo_stream_save rescue false) && (helpers.current_user.id.present? rescue false)
143
80
 
144
- if save_action && turbo_redirect_on_success_to.present?
81
+ if save_action && if_success_turbo_redirect_to.present?
145
82
  response.status = 302
146
- flash[:alert] = flash_alerts
147
- flash[:notice] = flash_notices
148
- Rails.logger.debug(" • Set flash[:alert] => #{flash_alerts}") if flash_alerts.present?
149
- Rails.logger.debug(" • Set flash[:notice] => #{flash_notices}") if flash_notices.present?
83
+ flash[:alert] = flashes[:alerts]
84
+ flash[:notice] = flashes[:notices]
85
+ Rails.logger.debug(" • Set flash[:alert] => #{flashes[:alerts]}") if flashes[:alerts].present?
86
+ Rails.logger.debug(" • Set flash[:notice] => #{flashes[:notices]}") if flashes[:notices].present?
150
87
  render_turbo_stream([
151
88
  [
152
89
  :redirect_to,
153
- turbo_redirect_on_success_to
90
+ if_success_turbo_redirect_to
154
91
  ]
155
92
  ])
156
- elsif save_action && redirect_on_success_to.present?
93
+ elsif save_action && if_success_redirect_to.present?
157
94
  response.status = 302
158
- if (Rails.configuration.x.render_turbo_stream.use_channel_for_turbo_stream_save rescue false) && (helpers.current_user.id.present? rescue false)
159
- streams.each do |s|
160
- next unless s.is_a?(Hash)
161
- Rails.logger.debug(" • Send by Cable => «#{s}»")
162
- render_to_me(
163
- s[:id],
164
- flash_action,
165
- partial: s[:partial],
166
- locals: s[:locals]
167
- )
168
- end
169
-
95
+ if allow_channel
96
+ Rails.logger.debug(" • Sent #{streams.length} actions through Turbo::StreamsChannel to enable defined redirection because allowed in configs.")
97
+ c_libs = RenderTurboStream::ChannelLibs.new(response)
98
+ c_libs.send_actions_to_channel("authenticated-user-#{helpers.current_user.id}", streams, @render_turbo_stream_evaluate_instance_variables)
170
99
  else
171
100
  flash[:alert] = flash_alerts
172
101
  flash[:notice] = flash_notices
173
102
  Rails.logger.debug(" • Set flash[:alert] => #{flash_alerts}") if flash_alerts.present?
174
103
  Rails.logger.debug(" • Set flash[:notice] => #{flash_notices}") if flash_notices.present?
175
104
  end
176
- redirect_to redirect_on_success_to
105
+ redirect_to if_success_redirect_to
106
+
107
+ elsif !target_id.present? && allow_channel
108
+ Rails.logger.debug(" • Sent #{streams.length} actions through Turbo::StreamsChannel because no target_id defined and allowed in configs.")
109
+ c_libs = RenderTurboStream::ChannelLibs.new(response)
110
+ c_libs.send_actions_to_channel("authenticated-user-#{helpers.current_user.id}", streams, @render_turbo_stream_evaluate_instance_variables)
177
111
 
178
112
  else
179
- flash.now[:alert] = flash_alerts
180
- flash.now[:notice] = flash_notices
181
113
  render_turbo_stream(streams)
182
114
  end
183
115
  end
184
116
 
185
-
186
117
  # renders a array of partials to send by turbo-stream and / or actions like turbo_power gem includes, to turbo_stream
187
118
  def render_turbo_stream(array)
188
119
 
@@ -192,12 +123,12 @@ module RenderTurboStream
192
123
  Rails.logger.warn " WARNING render_turbo_stream: Empty element inside attributes: «#{array}»"
193
124
  elsif pr.is_a?(Hash)
194
125
  props = pr.symbolize_keys
195
- raise "missing attribute :id in #{props}" if !props[:id].present?
196
- part = (props[:partial].present? ? props[:partial] : props[:id]).gsub('-', '_')
197
- partial = (part.to_s.include?('/') ? part : [controller_path, part].join('/'))
198
126
  r = props
127
+ r[:target] = RenderTurboStream::Libs.target_id_to_target(props[:target_id]) if props[:target_id].present?
128
+ raise "Missing attribute :target in #{props}" if !props[:target].present?
129
+ r.delete(:target_id)
199
130
  r[:action] = (props[:action].present? ? props[:action] : :replace)
200
- r[:partial] = partial
131
+ r[:partial] = RenderTurboStream::Libs.partial_path(props[:target], props[:target_id], controller_path, props[:partial])
201
132
  r[:type] = 'stream-partial'
202
133
  ary.push(r)
203
134
  elsif pr.is_a?(Array)
@@ -219,16 +150,11 @@ module RenderTurboStream
219
150
 
220
151
  # renders a partial to turbo_stream
221
152
 
222
- def stream_partial(
223
- id,
224
- partial: nil, #=> default: id
225
- action: :replace,
226
- locals: {}
227
- )
153
+ def stream_partial( target_id, partial: nil, action: :replace, locals: {} )
228
154
  render_turbo_stream(
229
155
  [
230
156
  {
231
- id: id,
157
+ target: RenderTurboStream::Libs.target_id_to_target(target_id),
232
158
  partial: partial,
233
159
  action: action,
234
160
  locals: locals
@@ -0,0 +1,162 @@
1
+ module RenderTurboStream
2
+ class ControllerLibs
3
+
4
+ def initialize(save_action)
5
+ @save_action = save_action
6
+ end
7
+
8
+ def generate_flash( model_name, controller_action, if_success_notices, if_error_alerts, add_notices, add_alerts )
9
+
10
+ target_id = (Rails.configuration.x.render_turbo_stream.flash_target_id rescue nil)
11
+ raise "Missing configuration: config.x.render_turbo_stream.flash_target_id" unless target_id
12
+ partial = Rails.configuration.x.render_turbo_stream.flash_partial
13
+ raise "Missing configuration: configuration.x.render_turbo_stream.flash_partial" unless partial
14
+ turbo_action = Rails.configuration.x.render_turbo_stream.flash_turbo_action
15
+ raise "Missing configuration: configuration.x.render_turbo_stream.flash_turbo_action" unless turbo_action
16
+
17
+
18
+ if @save_action
19
+ notices = if if_success_notices
20
+ if_success_notices
21
+ elsif controller_action.to_sym == :create
22
+ str = I18n.t(
23
+ 'activerecord.success.successfully_created',
24
+ default: '%<model_name>s successfully created'
25
+ )
26
+ [format(str, model_name: model_name)]
27
+ elsif controller_action.to_sym == :update
28
+ str = I18n.t(
29
+ 'activerecord.success.successfully_updated',
30
+ default: '%<model_name>s successfully updated'
31
+ )
32
+ [format(str, model_name: model_name)]
33
+ else
34
+ str = I18n.t(
35
+ "activerecord.success.#{controller_action}",
36
+ default: '%<model_name>s successfully updated'
37
+ )
38
+ [format(str, model_name: model_name)]
39
+ end
40
+ alerts = []
41
+ else
42
+ alerts = if if_error_alerts
43
+ if_error_alerts
44
+ elsif controller_action.to_sym == :create
45
+ str = I18n.t(
46
+ 'activerecord.errors.messages.could_not_create',
47
+ default: '%<model_name>s could not be created'
48
+ )
49
+ [format(str, model_name: model_name)]
50
+ elsif controller_action.to_sym == :update
51
+ str = I18n.t(
52
+ 'activerecord.errors.messages.could_not_update',
53
+ default: '%<model_name>s could not be updated'
54
+ )
55
+ [format(str, model_name: model_name)]
56
+ else
57
+ str = I18n.t(
58
+ "activerecord.errors.messages.#{controller_action}",
59
+ default: '%<model_name>s could not be updated'
60
+ )
61
+ [format(str, model_name: model_name)]
62
+ end
63
+ notices = []
64
+ end
65
+
66
+ turbo_actions = []
67
+ notices += add_notices.to_a
68
+ alerts += add_alerts.to_a
69
+ notices.each do |notice|
70
+ next unless notice.present?
71
+ flash_stream = {
72
+ target: RenderTurboStream::Libs.target_id_to_target(target_id),
73
+ partial: partial,
74
+ action: turbo_action,
75
+ locals: { success: true, message: notice }
76
+ }
77
+ turbo_actions.push(flash_stream)
78
+ end
79
+ alerts.each do |alert|
80
+ next unless alert.present?
81
+ flash_stream = {
82
+ target: RenderTurboStream::Libs.target_id_to_target(target_id),
83
+ partial: partial,
84
+ action: turbo_action,
85
+ locals: { success: false, message: alert }
86
+ }
87
+ turbo_actions.push(flash_stream)
88
+ end
89
+ { turbo_actions: turbo_actions, alerts: alerts, notices: notices }
90
+ end
91
+
92
+ def additional_actions( if_success, if_error, add )
93
+
94
+ (@save_action ? make_actions(if_success) : make_actions(if_error)) + make_actions(add)
95
+
96
+ end
97
+
98
+ def generate_action( controller_path, target_id, action, partial, locals )
99
+ libs = RenderTurboStream::Libs
100
+ target = libs.target_id_to_target(target_id)
101
+ _partial = libs.partial_path(nil, target_id, controller_path, partial)
102
+ [target: target, partial: _partial, locals: locals, action: action]
103
+ end
104
+
105
+ def action_errors(actions)
106
+ r = []
107
+ actions.each do |a|
108
+ if a.is_a?(Hash)
109
+ unless a[:target].present?
110
+ r.push("Missing attribute :target for => «#{a}»")
111
+ end
112
+ unless a[:partial].present?
113
+ r.push("Missing attribute :partial for => «#{a}»")
114
+ end
115
+ unless a[:action].present?
116
+ r.push("Missing attribute :action for => «#{a}»")
117
+ end
118
+ elsif a.is_a?(Array)
119
+ unless a.first.is_a?(String) || a.first.is_a?(Symbol)
120
+ r.push("Assuming a command, but the first attribute must be a string or symbol => «#{a}»")
121
+ end
122
+ end
123
+ end
124
+ r
125
+ end
126
+
127
+ private
128
+
129
+ # streamline actions to array
130
+ # valid inputs for if_success or if_error or add
131
+ # [:add_css_class, ...]
132
+ # [[:add_css_class, ..], ..]
133
+ # {target_id: '..', ..}
134
+ # [{target_id: '..', ..}, ..]
135
+
136
+ def make_actions(actions)
137
+ res = if actions.present?
138
+ if actions.is_a?(Hash)
139
+ [actions]
140
+ elsif actions.is_a?(Array)
141
+ if actions.first.is_a?(String) || actions.first.is_a?(Symbol)
142
+ [actions]
143
+ else
144
+ actions
145
+ end
146
+ end
147
+ else
148
+ []
149
+ end
150
+ res.map do |a|
151
+ if a.is_a?(Hash) && a.key?(:target_id)
152
+ a = a.merge(target: "##{a[:target_id]}")
153
+ a.delete(:target_id)
154
+ a
155
+ else
156
+ a
157
+ end
158
+ end
159
+ end
160
+
161
+ end
162
+ end
@@ -0,0 +1,35 @@
1
+ module RenderTurboStream
2
+ class Libs
3
+
4
+ def self.target_id_to_target(target_id)
5
+ if target_id.present?
6
+ "##{target_id}"
7
+ else
8
+ nil
9
+ end
10
+ end
11
+
12
+ def self.target_to_target_id(target)
13
+ if target.present? && target.to_s[0] == '#'
14
+ target[1..-1]
15
+ else
16
+ nil
17
+ end
18
+ end
19
+
20
+ def self.partial_path(target, target_id, controller_path, partial)
21
+ if partial && partial.to_s.include?('/')
22
+ partial
23
+ elsif partial.present?
24
+ [controller_path, partial].join('/')
25
+ elsif target_id.present?
26
+ [controller_path, target_id.gsub('-', '_')].join('/')
27
+ elsif target.present?
28
+ [controller_path, RenderTurboStream::Libs.target_to_target_id(target).gsub('-', '_')].join('/')
29
+ end
30
+ end
31
+
32
+
33
+
34
+ end
35
+ end