app/channels/stimulus_reflex/channel.rb in stimulus_reflex-3.4.2 vs app/channels/stimulus_reflex/channel.rb in stimulus_reflex-3.5.0.pre0
- old
+ new
@@ -1,61 +1,39 @@
# frozen_string_literal: true
class StimulusReflex::Channel < StimulusReflex.configuration.parent_channel.constantize
+ attr_reader :reflex_data
+
def stream_name
ids = connection.identifiers.map { |identifier| send(identifier).try(:id) || send(identifier) }
[
params[:channel],
ids.select(&:present?).join(";")
].select(&:present?).join(":")
end
def subscribed
super
- fix_environment!
stream_from stream_name
end
def receive(data)
- url = data["url"].to_s
- selectors = (data["selectors"] || []).select(&:present?)
- selectors = data["selectors"] = ["body"] if selectors.blank?
- target = data["target"].to_s
- factory = StimulusReflex::ReflexFactory.new(target)
- reflex_class = factory.call
- method_name = factory.method_name
- arguments = (data["args"] || []).map { |arg| object_with_indifferent_access arg }
- element = StimulusReflex::Element.new(data)
- permanent_attribute_name = data["permanentAttributeName"]
- form_data = Rack::Utils.parse_nested_query(data["formData"])
- params = form_data.deep_merge(data["params"] || {})
-
+ @reflex_data = StimulusReflex::ReflexData.new(data)
begin
begin
- reflex = reflex_class.new(self,
- url: url,
- element: element,
- selectors: selectors,
- method_name: method_name,
- params: params,
- client_attributes: {
- reflex_id: data["reflexId"],
- xpath_controller: data["xpathController"],
- xpath_element: data["xpathElement"],
- reflex_controller: data["reflexController"],
- permanent_attribute_name: permanent_attribute_name
- })
- delegate_call_to_reflex reflex, method_name, arguments
- rescue => invoke_error
- message = exception_message_with_backtrace(invoke_error)
- body = "Reflex #{target} failed: #{message} [#{url}]"
+ reflex = StimulusReflex::ReflexFactory.create_reflex_from_data(self, @reflex_data)
+ delegate_call_to_reflex reflex
+ rescue => exception
+ error = exception_with_backtrace(exception)
+ error_message = "\e[31mReflex #{reflex_data.target} failed: #{error[:message]} [#{reflex_data.url}]\e[0m\n#{error[:stack]}"
if reflex
- reflex.rescue_with_handler(invoke_error)
- reflex.broadcast_message subject: "error", body: body, data: data, error: invoke_error
+ reflex.rescue_with_handler(exception)
+ puts error_message
+ reflex.broadcast_message subject: "error", data: data, error: exception
else
- puts "\e[31m#{body}\e[0m"
+ puts error_message
if body.to_s.include? "No route matches"
initializer_path = Rails.root.join("config", "initializers", "stimulus_reflex.rb")
puts <<~NOTE
@@ -81,62 +59,62 @@
if reflex.halted?
reflex.broadcast_message subject: "halted", data: data
else
begin
- reflex.broadcast(selectors, data)
- rescue => render_error
- reflex.rescue_with_handler(render_error)
- message = exception_message_with_backtrace(render_error)
- body = "Reflex failed to re-render: #{message} [#{url}]"
- reflex.broadcast_message subject: "error", body: body, data: data, error: render_error
- puts "\e[31m#{body}\e[0m"
+ reflex.broadcast(reflex_data.selectors, data)
+ rescue => exception
+ reflex.rescue_with_handler(exception)
+ error = exception_with_backtrace(exception)
+ reflex.broadcast_message subject: "error", data: data, error: exception
+ puts "\e[31mReflex failed to re-render: #{error[:message]} [#{reflex_data.url}]\e[0m\n#{error[:stack]}"
end
end
ensure
if reflex
commit_session(reflex)
- reflex.logger.print
+ report_failed_basic_auth(reflex) if reflex.controller?
+ reflex.logger&.print
end
end
end
private
- def object_with_indifferent_access(object)
- return object.with_indifferent_access if object.respond_to?(:with_indifferent_access)
- object.map! { |obj| object_with_indifferent_access obj } if object.is_a?(Array)
- object
- end
-
- def delegate_call_to_reflex(reflex, method_name, arguments = [])
+ def delegate_call_to_reflex(reflex)
+ method_name = reflex_data.method_name
+ arguments = reflex_data.arguments
method = reflex.method(method_name)
- required_params = method.parameters.select { |(kind, _)| kind == :req }
- optional_params = method.parameters.select { |(kind, _)| kind == :opt }
- if arguments.size == 0 && required_params.size == 0
+ policy = StimulusReflex::ReflexMethodInvocationPolicy.new(method, arguments)
+
+ if policy.no_arguments?
reflex.process(method_name)
- elsif arguments.size >= required_params.size && arguments.size <= required_params.size + optional_params.size
+ elsif policy.arguments?
reflex.process(method_name, *arguments)
else
raise ArgumentError.new("wrong number of arguments (given #{arguments.inspect}, expected #{required_params.inspect}, optional #{optional_params.inspect})")
end
end
def commit_session(reflex)
store = reflex.request.session.instance_variable_get("@by")
store.commit_session reflex.request, reflex.controller.response
- rescue => e
- message = "Failed to commit session! #{exception_message_with_backtrace(e)}"
- puts "\e[31m#{message}\e[0m"
+ rescue => exception
+ error = exception_with_backtrace(exception)
+ puts "\e[31mFailed to commit session! #{error[:message]}\e[0m\n#{error[:backtrace]}"
end
- def exception_message_with_backtrace(exception)
- "#{exception}\n#{exception.backtrace.first}"
+ def report_failed_basic_auth(reflex)
+ if reflex.controller.response.status == 401
+ puts "\e[31mReflex failed to process controller action \"#{reflex.controller.class}##{reflex.controller.action_name}\" due to HTTP basic auth. Consider adding \"unless: -> { @stimulus_reflex }\" to the before_action or method responible for authentication.\e[0m"
+ end
end
- def fix_environment!
- ([ApplicationController] + ApplicationController.descendants).each do |controller|
- controller.renderer.instance_variable_set(:@env, connection.env.merge(controller.renderer.instance_variable_get(:@env)))
- end
+ def exception_with_backtrace(exception)
+ {
+ message: exception.to_s,
+ backtrace: exception.backtrace.first,
+ stack: exception.backtrace.join("\n")
+ }
end
end