February 5, 2009
How does Rails handle exceptions ?
Rails exception handling depends on two factors and we are going to discuss both of them here.
# ~/lib/action_controller/rescue.rb
if consider_all_requests_local || local_request?
rescue_action_locally(exception)
else
rescue_action_in_public(exception)
end
When exceptions are handled by rescue_action_locally
then we get to see the
page with stacktrace. When exceptions are handled by rescue_action_in_public
,
we get to see the public/500.html
or an error page matching the error code.
As you can see Rails uses two different methods consider_all_requests_local
and local_request?
to decide how exception should be handled.
consider_all_requests_local
is a class level variable for
ActionController::Base
. We hardly pay attention to it but it is configured
through files residing in config/environments
# config/environments/development.rb
config.action_controller.consider_all_requests_local = true
# config/environments/production.rb
config.action_controller.consider_all_requests_local = false
As you can see in development environment all the requests are considered local.
That is a common question I see in the mailing list. As you can see the condition to decide how to handle exception is
if consider_all_requests_local || local_request?
In development environment consider_all_requests_local
is always true as I
showed before. Since one of the conditions is true Rails always handles the
exception using rescue_action_locally
.
Same issue. In this case you are running in production mode so
consider_all_requests_local
is false
but local_request? is still true
because of localhost.
Recently I started using hoptoad and I needed to test how hoptoad will handle
exception in production mode. However without any change local_request? was
always returning true for http://localhost:30000
.
Then I stick following file under config/initializers
# config/initializers/local_request_override.rb
module CustomRescue
def local_request?
return false if Rails.env.production? || Rails.env.staging?
super
end
end
ActionController::Base.class_eval do
include CustomRescue
end
Now all request in production or in staging mode are treated as NOT local.
Now in both staging
and production
mode I get to see 500.html page even if I
am accessing the application from http://localhost:3000
.
If this blog was helpful, check out our full blog archive.