class RailsDynamicErrors::DynamicErrors
This is a Rack compatible middleware that implements the key functionality of the rails_dynamic_errors gem. It serves two roles:
-
intercept unhandled exceptions and error conditions from the Rail application it is inserted into
-
generate dynamic error pages for the exceptions and error conditions it is configured to
The middleware is inserted into the Rails application’s middleware stack automatically. As such, the end user should never need to use it directly.
In order to avoid disrupting standard Rails functionality, this middleware respects the Rails exception handling related configuration options. As such, it will only process exceptions and error conditions if:
-
the request is not local (action_dispatch.show_detailed_exceptions is false)
-
the environment is set to display exceptions (rather than raise them)
Configuration of which exceptions and error conditions to catch is done within the main Rails application’s configuration, using an option set namespaced to rails_dynamic_errors. Specifically:
Rails.application.config.rails_dynamic_errors.http_error_status_codes_to_handle
This option must be an array of integer HTTP error status codes (404, etc.)
Public Class Methods
Initialize the middleware (standard Rack method)
# File lib/rails_dynamic_errors/middleware/dynamic_errors.rb, line 27 def initialize(app) @app = app end
Public Instance Methods
Call the middleware (standard Rack method)
# File lib/rails_dynamic_errors/middleware/dynamic_errors.rb, line 32 def call(env) response = @app.call(env) # 404 errors for unmatched routes aren't actually raised until # ActionDispatch::DebugExceptions. If we're supposed to catch 404s and # the application indicates there was no matching route, throw and # handle a 404 generating exception if can_process_exceptions?(env) && catch_not_found_error? && request_unhandled?(response) raise ActionController::RoutingError.new("No route matches [#{env['REQUEST_METHOD']}] #{env['PATH_INFO'].inspect}") else response end rescue Exception => exception if can_process_exceptions?(env) process_exception(env, exception) else raise exception end end
Private Instance Methods
# File lib/rails_dynamic_errors/middleware/dynamic_errors.rb, line 60 def can_handle_http_error_status_code?(status_code) http_error_status_codes_to_handle.include?(status_code) end
# File lib/rails_dynamic_errors/middleware/dynamic_errors.rb, line 52 def can_process_exceptions?(env) ! env['action_dispatch.show_detailed_exceptions'] && env['action_dispatch.show_exceptions'] end
# File lib/rails_dynamic_errors/middleware/dynamic_errors.rb, line 56 def catch_not_found_error? can_handle_http_error_status_code?(404) end
# File lib/rails_dynamic_errors/middleware/dynamic_errors.rb, line 93 def dynamic_error_path(status_code) # Error page routes need to reflect where the engine has been mounted "#{RailsDynamicErrors::Engine.mounted_at}/#{status_code}" end
# File lib/rails_dynamic_errors/middleware/dynamic_errors.rb, line 82 def exception_http_error_status_code(env, exception) wrapper = ActionDispatch::ExceptionWrapper.new(env, exception) wrapper.status_code end
# File lib/rails_dynamic_errors/middleware/dynamic_errors.rb, line 87 def generate_dynamic_error_page(env, exception, status_code) env['PATH_INFO'] = dynamic_error_path(status_code) env['action_dispatch.exception'] = exception Rails.application.routes.call(env) end
# File lib/rails_dynamic_errors/middleware/dynamic_errors.rb, line 64 def http_error_status_codes_to_handle Rails.application.config.rails_dynamic_errors.http_error_status_codes_to_handle || [] end
# File lib/rails_dynamic_errors/middleware/dynamic_errors.rb, line 73 def process_exception(env, exception) status_code = exception_http_error_status_code(env, exception) if can_handle_http_error_status_code?(status_code) generate_dynamic_error_page(env, exception, status_code) else raise exception end end
# File lib/rails_dynamic_errors/middleware/dynamic_errors.rb, line 68 def request_unhandled?(response) # Returned by Rails when no matching route was found [404, {'X-Cascade' => 'pass'}, ['Not Found']] == response end