Ruby on Rails
HandlingPreControllerErrors

Related to HowtoConfigureTheErrorPageForYourRailsApp.

Some errors can occur before any controller is loaded. In those cases, nothing defined in ApplicationController will help, since the controller isn’t around to deal with the exception. To deal with this you can redefine rescue_action_in_public in ActionController::Base in a separate file and pull it in through /config/environment.rb.

/config/environment.rb


# Include your app's configuration here:
require 'error_handler_basic' # defines AC::Base#rescue_action_in_public

/lib/error_handler_basic.rb


class ActionController::Base
  def rescue_action_in_public(exception)
    render :text => <<TOKEN 
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
...
<!--  #{exception}  --></body></html>
TOKEN
  end  
end

Pre-Pre-controller

The above advice doesn’t always help, since in many cases where an error happens too early to be handled by your controller’s rescue_action_* method, it will also be too early to be handled by ActionController::Base#rescue_action_in_public. An example of such an error is if an error occurs while recreating the session object. Rails doesn’t seem to provide any clean way to handle these errors, they just result in an exception escaping the Dispatcher.dispatch method, which is handled in a different way depending what web server you’re running under. I override the Dispatcher.dispatch method with a version which has an extra level of error handling to catch more errors and handle them in a web-server independent way. Add this to your environment.rb, and modify to your taste:

class << Dispatcher
  def dispatch(cgi = CGI.new,
               session_options = ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS)
    begin
      request, response =
        ActionController::CgiRequest.new(cgi, session_options),
        ActionController::CgiResponse.new(cgi)
      prepare_application
      ActionController::Routing::Routes.recognize!(request).process(request, response).out
    rescue Object => exception
      begin
        ActionController::Base.process_with_exception(request, response, exception).out
      rescue
        # The rescue action above failed also, probably for the same reason
        # the original action failed.  Do something simple which is unlikely
        # to fail.  You might want to redirect to a static page instead of this.
        e = exception
        cgi.header("type" => "text/html")
        cgi.out('cookie' => '') do
          <<-RESPONSE
        <html>
          <head><title>Application Error</title></head>
          <body>
            <h1>Application Error</h1>
            <b><pre>#{e.class}: #{e.message}</pre></b>

            <pre>#{e.backtrace.join("\n")}</pre>
          </body>
        </html>
          RESPONSE
        end
      end
    ensure
      reset_application
    end
  end
end

Can this be used to redirect to a controller action?