Module: RenderTurboStream::ControllerHelpers

Defined in:
lib/render_turbo_stream/controller_helpers.rb

Instance Method Summary collapse

Instance Method Details

#render_turbo_stream(array) ⇒ Object

renders a array of partials to send by turbo-stream and / or actions like turbo_power gem includes, to turbo_stream



145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
# File 'lib/render_turbo_stream/controller_helpers.rb', line 145

def render_turbo_stream(array)

  ary = []
  array.each do |pr|
    cmd = nil
    if !pr.present?
      Rails.logger.warn "  WARNING render_turbo_stream: Empty element inside attributes: «#{array}»"
    elsif pr.is_a?(Hash)
      props = pr.symbolize_keys
      r = props
      if props[:target_id].present?
        r[:target] = RenderTurboStream::Libs.target_id_to_target(props[:target_id])
      else
        r[:target] = props[:target]
      end
      r.delete(:target_id)
      r[:action] = (props[:action].present? ? props[:action] : :replace)
      if props[:partial].present?
        r[:partial] = RenderTurboStream::Libs.partial_path(controller_path, props[:partial])
      else
        r[:template] = RenderTurboStream::Libs.partial_path(controller_path, props[:template])
      end
      r[:type] = 'stream-partial'

      cmd = r
    elsif pr.is_a?(Array)
      raise "array has to contain at least one element: #{pr}" unless pr.first.present?
      cmd = pr
    else
      raise "ERROR render_turbo_stream invalid type: Only hash or array allowed"
    end
    ary.push(cmd) if cmd
    Rails.logger.debug("  • Stream => #{cmd}")
  end




  #if request.format.to_sym == :turbo_stream
    render template: 'render_turbo_stream', locals: { streams: ary }, layout: false, formats: :turbo_stream
  # else
  #   Rails.logger.debug("  • Render Turbo Stream RENDERING AS HTML because request.format => #{request.format}")
  #   render template: 'render_turbo_stream_request_test', locals: { streams: ary }, layout: false, formats: :html
  # end


end

#stream_partial(partial, id: nil, action: :replace, locals: {}) ⇒ Object



193
194
195
# File 'lib/render_turbo_stream/controller_helpers.rb', line 193

def stream_partial(partial, id: nil, action: :replace, locals: {})
  render_turbo_stream([{ partial: partial, locals: locals, id: id, action: action }])
end

#turbo_stream_save(save_action, object: nil, if_success_redirect_to: nil, if_success_turbo_redirect_to: nil, target_id: nil, partial: nil, action: 'replace', locals: {}, if_success_add: nil, if_error_add: nil, add: [], if_success_notices: nil, if_error_alerts: nil, add_notices: nil, add_alerts: nil, flash_controller_action_name: action_name) ⇒ Object

Handles translated flash messages as defined in translations and configs. 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. you can add more stream actions to the same response



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/render_turbo_stream/controller_helpers.rb', line 13

def turbo_stream_save(
  save_action,
  object: nil, # object used in save_action, example: @customer

  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. Value can be given as block like "->{article_path(@article)}"
  if_success_turbo_redirect_to: nil, # does a full page redirect (break out of all frames by turbo_power redirect). Value can be given as block like "->{article_path(@article)}"

  target_id: nil, # IF NIL: the gem grabs inside the rendered content for turbo-frame tag or turbo-target (element from helper of this gem) tag and takes the id from there.
  partial: nil, # if nil: the gem renders the default template by turbo-stream
  action: 'replace', # options: append, prepend
  locals: {},

  if_success_add: nil, # hash for a partial to render or array with actions (as array) or hashes for partials within
  if_error_add: nil, # additional partials that should be rendered if save_action failed
  add: [], # additional streams

  if_success_notices: nil, # array of strings, or string, override default generated flash generation in the case of success
  if_error_alerts: nil,
  add_notices: nil, # array of strings
  add_alerts: nil,

  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}"
)

  # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  #                    LOGIC
  # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

  unless object
    object = eval("@#{controller_name.classify.underscore}")
  end
  unless object
    raise "Could not fetch a model name by «eval(\"\@\#{controller_name.classify.underscore}\")». You must provide the argument :object."
  end

  libs = RenderTurboStream::ControllerLibs.new(save_action)
  model_name = object.model_name.human

  streams = []

  flashes = libs.generate_flash(
    model_name,
    flash_controller_action_name,
    if_success_notices,
    if_error_alerts,
    add_notices,
    add_alerts,
  )
  streams += flashes[:turbo_actions]

  streams += libs.additional_actions(
    if_success_add,
    if_error_add,
    add
  )

  if libs.action_errors(streams).present?
    raise libs.action_errors(streams).join(', ')
  end

  if save_action
    if Rails.configuration.x.store_last_saved_object && object.id
      begin
        session['last_saved_object'] = object.to_global_id
      rescue
        Rails.logger.debug("session['last_saved_object'] = ... failed. You may be in test environent?")
      end
    end
  else
    response.status = 422
    RenderTurboStream::Libs.debug_save_errors(object, flash_controller_action_name)
  end

  # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  #==                      RENDER TO STREAM
  # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

  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)

  if save_action && if_success_turbo_redirect_to.present?
    response.status = 303
    flash[:alert] = flashes[:alerts]
    flash[:notice] = flashes[:notices]
    Rails.logger.debug("  • Successful saved && Redirect by «turbo_redirect_to»")
    Rails.logger.debug("  • Set flash[:alert] => #{flashes[:alerts]}") if flashes[:alerts].present?
    Rails.logger.debug("  • Set flash[:notice] => #{flashes[:notices]}") if flashes[:notices].present?

    if if_success_turbo_redirect_to.is_a?(Proc)
      redirect_path = if_success_turbo_redirect_to.call
    else
      redirect_path = if_success_turbo_redirect_to
    end

    render_turbo_stream([
                          [
                            :redirect_to,
                            redirect_path
                          ]
                        ])

  elsif save_action && if_success_redirect_to.present?
    response.status = 303

    if allow_channel

      Rails.logger.debug("  • Send actions through Turbo::StreamsChannel")
      c_libs = RenderTurboStream::ChannelLibs.new
      c_libs.send_actions_to_channel("authenticated_user_#{helpers.current_user.id}", streams)
      RenderTurboStream::Test::Request::Libs.set_test_responses(response, c_libs.test_responses)
    else
      flash[:alert] = flashes[:alerts]
      flash[:notice] = flashes[:notices]
      Rails.logger.debug("  • Turbo::StreamsChannel NOT ALLOWED BY CONFIGS!")
      Rails.logger.debug("  • Set flash[:alert] => #{flashes[:alerts]}") if flashes[:alerts].present?
      Rails.logger.debug("  • Set flash[:notice] => #{flashes[:notices]}") if flashes[:notices].present?
      Rails.logger.debug("  • Could not send #{streams.length} actions => #{streams}")
    end
    if if_success_redirect_to.is_a?(Proc)
      redirect_to if_success_redirect_to.call
    else
      redirect_to if_success_redirect_to
    end

  else
    Rails.logger.debug("  • Respond by TurboStream in #{streams.length} #{'action'.pluralize(streams.length)}")
    streams += libs.generate_action(controller_path, target_id, action, partial, (partial ? nil : action_name), locals)
    render_turbo_stream(streams)

  end
end