Class: TurboBoost::Commands::Runner

Inherits:
Object
  • Object
show all
Defined in:
lib/turbo_boost/commands/runner.rb

Constant Summary collapse

RESPONSE_HEADER =
"TurboBoost-Command"
SUPPORTED_MEDIA_TYPES =
{
  "text/html" => true,
  "text/vnd.turbo-boost.html" => true,
  "text/vnd.turbo-stream.html" => true
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(controller) ⇒ Runner

Returns a new instance of Runner.



19
20
21
22
# File 'lib/turbo_boost/commands/runner.rb', line 19

def initialize(controller)
  @controller = controller
  @responder = TurboBoost::Commands::Responder.new
end

Instance Attribute Details

#controllerObject (readonly)

Returns the value of attribute controller.



17
18
19
# File 'lib/turbo_boost/commands/runner.rb', line 17

def controller
  @controller
end

#errorObject (readonly)

Returns the value of attribute error.



17
18
19
# File 'lib/turbo_boost/commands/runner.rb', line 17

def error
  @error
end

#responderObject (readonly)

Returns the value of attribute responder.



17
18
19
# File 'lib/turbo_boost/commands/runner.rb', line 17

def responder
  @responder
end

Instance Method Details

#command_aborted?Boolean

Returns:

  • (Boolean)


75
76
77
# File 'lib/turbo_boost/commands/runner.rb', line 75

def command_aborted?
  !!command_instance&.aborted?
end

#command_classObject



55
56
57
# File 'lib/turbo_boost/commands/runner.rb', line 55

def command_class
  @command_class ||= command_class_name&.safe_constantize
end

#command_class_nameObject



42
43
44
45
46
47
# File 'lib/turbo_boost/commands/runner.rb', line 42

def command_class_name
  return nil unless command_requested?
  name = command_name.split("#").first
  name << "Command" unless name.end_with?("Command")
  name
end

#command_errored?Boolean

Returns:

  • (Boolean)


79
80
81
82
# File 'lib/turbo_boost/commands/runner.rb', line 79

def command_errored?
  return false if command_aborted?
  command_instance&.errored? || error.present?
end

#command_instanceObject



59
60
61
62
63
# File 'lib/turbo_boost/commands/runner.rb', line 59

def command_instance
  @command_instance ||= command_class&.new(controller, state, command_params).tap do |instance|
    instance&.add_observer self, :handle_command_event
  end
end

#command_method_nameObject



49
50
51
52
53
# File 'lib/turbo_boost/commands/runner.rb', line 49

def command_method_name
  return nil unless command_requested?
  return "perform" unless command_name.include?("#")
  command_name.split("#").last
end

#command_nameObject



37
38
39
40
# File 'lib/turbo_boost/commands/runner.rb', line 37

def command_name
  return nil unless command_requested?
  command_params[:name]
end

#command_paramsObject



32
33
34
35
# File 'lib/turbo_boost/commands/runner.rb', line 32

def command_params
  return ActionController::Parameters.new.permit! unless command_requested?
  @command_params ||= ActionController::Parameters.new(parsed_command_params).permit!
end

#command_performed?Boolean

Returns:

  • (Boolean)


88
89
90
# File 'lib/turbo_boost/commands/runner.rb', line 88

def command_performed?
  command_instance&.performed? || command_errored?
end

#command_performing?Boolean

Returns:

  • (Boolean)


84
85
86
# File 'lib/turbo_boost/commands/runner.rb', line 84

def command_performing?
  !!command_instance&.performing?
end

#command_requested?Boolean

Returns:

  • (Boolean)


28
29
30
# File 'lib/turbo_boost/commands/runner.rb', line 28

def command_requested?
  controller.request.env.key?("turbo_boost_command_params") || controller.params.key?("turbo_boost_command")
end

#command_succeeded?Boolean

Returns:

  • (Boolean)


92
93
94
# File 'lib/turbo_boost/commands/runner.rb', line 92

def command_succeeded?
  !!command_instance&.succeeded?
end

#command_valid?Boolean

Returns:

  • (Boolean)


65
66
67
68
69
70
71
72
73
# File 'lib/turbo_boost/commands/runner.rb', line 65

def command_valid?
  return false unless command_requested?

  validator = TurboBoost::Commands::CommandValidator.new(command_instance, command_method_name)
  raise_on_invalid_command? ? validator.validate! : validator.valid?

  validator = TurboBoost::Commands::TokenValidator.new(command_instance, command_method_name)
  raise_on_invalid_command? ? validator.validate! : validator.valid?
end

#controller_action_allowed?Boolean

Returns:

  • (Boolean)


96
97
98
# File 'lib/turbo_boost/commands/runner.rb', line 96

def controller_action_allowed?
  !controller_action_prevented?
end

#controller_action_prevented?Boolean

Returns:

  • (Boolean)


100
101
102
# File 'lib/turbo_boost/commands/runner.rb', line 100

def controller_action_prevented?
  !!@controller_action_prevented
end

#flushObject

Always runs after the controller action has been performed



122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
# File 'lib/turbo_boost/commands/runner.rb', line 122

def flush
  return unless command_requested? # not a command request

  # global response components
  add_header
  add_state

  # mutually exclusive responses
  respond_with_abort if command_aborted?
  respond_with_error if command_errored?
  respond_with_success if command_succeeded?

  # store the responder for use in → TurboBoost::Commands::ExitMiddleware
  controller.request.env["turbo_boost_command_responder"] = responder
rescue => error
  Rails.logger.error "TurboBoost::Commands::Runner failed to update the response! #{error.message}"
end

#handle_command_event(*args) ⇒ Object



173
174
175
176
177
178
179
180
# File 'lib/turbo_boost/commands/runner.rb', line 173

def handle_command_event(*args)
  event = args.shift
  options = args.extract_options!
  case event
  when :aborted, :errored then prevent_controller_action error: options[:error]
  when :performed then prevent_controller_action if should_prevent_controller_action?
  end
end

#message_verifierObject



167
168
169
170
171
# File 'lib/turbo_boost/commands/runner.rb', line 167

def message_verifier
  ActiveSupport::MessageVerifier.new Rails.application.secret_key_base, digest: "SHA256", url_safe: true
rescue
  ActiveSupport::MessageVerifier.new Rails.application.secret_key_base, digest: "SHA256"
end

#prevent_controller_action(error: nil) ⇒ Object



140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/turbo_boost/commands/runner.rb', line 140

def prevent_controller_action(error: nil)
  return if controller_action_prevented?
  @controller_action_prevented = true
  @error = error

  status = case error
  when nil then response_status
  when TurboBoost::Commands::AbortError, TurboBoost::Commands::PerformError then error.http_status_code
  else :internal_server_error
  end

  flush
  render_response status: status
end

#render_response(html: "", status: nil) ⇒ Object

Renders the response body instead of the controller action. Invoked by: prevent_controller_action NOTE: Halts the Rails controller callback chain



158
159
160
161
# File 'lib/turbo_boost/commands/runner.rb', line 158

def render_response(html: "", status: nil)
  return if controller.performed?
  controller.render html: html, layout: false, status: status || response_status
end

#runObject



109
110
111
112
113
114
115
116
117
118
119
# File 'lib/turbo_boost/commands/runner.rb', line 109

def run
  return unless command_valid?
  return if command_aborted?
  return if command_errored?
  return if command_performing?
  return if command_performed?

  command_instance.perform_with_callbacks command_method_name
rescue => error
  prevent_controller_action error: error if command_requested?
end

#should_prevent_controller_action?Boolean

Returns:

  • (Boolean)


104
105
106
107
# File 'lib/turbo_boost/commands/runner.rb', line 104

def should_prevent_controller_action?
  return false unless command_performed?
  command_instance.should_prevent_controller_action? command_method_name
end

#stateObject



24
25
26
# File 'lib/turbo_boost/commands/runner.rb', line 24

def state
  @state ||= TurboBoost::Commands::State.new(command_params.fetch(:state, {}))
end

#turbo_streamObject



163
164
165
# File 'lib/turbo_boost/commands/runner.rb', line 163

def turbo_stream
  @turbo_stream ||= Turbo::Streams::TagBuilder.new(controller.view_context)
end