I wanted to improve error handling In my Rails applications. Specifically, I wanted three things:
- a custom error page that matched the site's design
- the errors to appear in the error log (production.log)
- email notification of server errors
Note: these steps are for Rails 2.3.2–2.3.8. Other versions may require different instructions.
Custom error page
Normally, when server error occurs, Rails renders public/500.html. You can customize this. However, if you include your site's layout information here, you violate the DRY principle.
- Create a directory for error templates
mkdir app/views/errors - Create the error file:
touch app/views/errors/500.html.erb - Remove the static file:
rm public/500.html - In
application_controller.rb, overriderender_optional_error_file:protected def render_optional_error_file(status_code) render :template => "errors/500", :status => 500, :layout => 'application' end
- To test your error handler in the development environment, in
application_controller.rb, add this line:alias_method :rescue_action_locally, :rescue_action_in_publicbe sure to comment this out when you're done, so you can see backtraces.
Logging errors
Because we overrode render_optional_error_file instead of using rescue_from (2), errors still go to the log (production.log).
Email notification
There's a terrific exception notification plugin that handles this for you.
This is a bit confusing, because there are three versions of the plugin floating around:
- The master version on github, for Rails 3
- A branch on github, for Rails 2.3
- The old version, which also works with Rails 2
Important If you install via the standard method (script/plugin install), you'll get an old version of the plugin, and the current instructions (on github) won't work. (See below for legacy instructions.)
If you install from github, you'll get a version for Rails 3 by default, and that won't work, either.
Here's what to do:
- Install the plugin from the 2-3-stable branch from github:
script/plugin install git://github.com/rails/exception_notification.git -r 2-3-stable - In
application_controller.rb, place this at the top:include ExceptionNotification::Notifiable - In
environment.rb, add these lines at the very end, after the|config|block:ExceptionNotification::Notifier.exception_recipients = %w([email protected]) ExceptionNotification::Notifier.sender_address = %("Application Error" <[email protected]>) ExceptionNotification::Notifier.email_prefix = "[Fancy App] "
-
To have sendmail send email (instead of using raw SMTP), add this line to
environment.rb:ActionMailer::Base.delivery_method = :sendmail
Legacy exception_notification instructions
- Install the plugin:
script/plugin install exception_notification - In
application_controller.rb, place this at the top:include ExceptionNotifiable - In
environment.rb, add these lines at the very end, after the|config|block:ExceptionNotifier.exception_recipients = %w([email protected]) ExceptionNotifier.sender_address = %("Application Error" <[email protected]>) ExceptionNotifier.email_prefix = "[Fancy App] "
Thanks for the post! After you put this in place, did you find that exception notification emailed you for 404s? I used what you did, but overwrote render_optional_error_file in a slightly different way and started getting notifications on 404s. Here’s what I did:
def render_optional_error_file(status_code) status = interpret_status(status_code)[0,3] if ["404", "422", "500"].include?(status) render :template => "/errors/#{status}.html.erb", :status => status else render :template => "/errors/unknown.html.erb", :status => status end endOh, I had effectively disabled 404s by redirecting everyone home:
map.connect '*path', :controller => :home, :action => :errorYour idea seems better.
Ah, gotcha. The problem with my approach was that I would get emailed on all 404s as well, which was driving me crazy. I narrowed the problem down to a method in exception notification:
def deliver_exception_notification?
!self.class.skip_exception_notifications? && ![404, "404 Not Found"].include?(response.status)
end
I overrode this method in my application_controller by simply changing 404 (int) to “404” (string). That worked (I’m getting emails on all errors now except for 404s), but I’m trying to figure out if that’s really a bug in exception notification and, if so, if I handled it correctly.
Thanks Paul and Jeremy for this post. It’s exactly what I was looking for
not working at all, I try to put an error on my apps in order to test it.
but it never send any email
What version of Rails are you using?