devroom.io/drafts/2011-10-14-rails-3-customized-exception-handling.md
Ariejan de Vroom dbae98c4c0 Moar updates
2013-03-24 14:27:51 +01:00

99 lines
3.1 KiB
Markdown

---
title: "Rails 3: Customized exception handling"
kind: article
slug: rails-3-customized-exception-handling
created_at: 2011-10-14
tags:
- Rails
- rails3
- exceptions
- error
- rescue
---
Exceptions happen. There's no way around that. But not all exceptions are created equally.
For instance, a 404 "Not found" error can (and should) be handled correctly in your application.
Let me give you an example of how to handle a `ActiveRecord::RecordNotFound` exception. Let's assume you have an application that could show a user profile:
:::ruby
# GET /p/:name
def show
@profile = Profile.find(params[:name])
end
Now, it may happen that the `:name` paramater contains a value that cannot be found in our database, most likely because someone made a typo in the URL.
If `Profile#find` cannot get a proper result it will throw `ActiveRecord::RecordNotFound`.
Now, instead of showing the user the (by default ugly) 404 page from `public/404.html` we want to do something more fancy.
## Action-specific exception handling
Here's one solution:
:::ruby
# GET /p/:name
def show
@profile = Profile.find(params[:name])
rescue
render :template => 'application/profile_not_found', :status => :not_found
end
You can now create `app/views/applicaiton/profile_not_found.html.haml` and give a nice custom error message to your user.
You may try to find some matching profiles to `:name` or show a search box.
## Global exception handling
The above example only works for the specific profile `show` action. It's also possible to hanlde exceptions on the application level.
Your `show` action still looks like this:
:::ruby
# GET /p/:name
def show
@profile = Profile.find(params[:name])
end
Then, in your `app/controllers/application_controller.rb` add this:
:::ruby
class ApplicationController < ActionController::Base
rescue_from ActiveRecord::RecordNotFound, :with => :rescue_not_found
protected
def rescue_not_found
render :template => 'application/not_found', :status => :not_found
end
end
Whenever an `ActiveRecord::RecordNotFound` exception is thrown (and not handled by the action itself), it will be handled by your `ApplicationController`.
## Custom exceptions
It's possible to throw your own custom exceptions and handle them in different ways. Like this:
:::ruby
# Define your own error
class MyApp::ProfileNotFoundError < StandardError
end
# GET /p/:name
def show
@profile = Profile.find_by_name(params[:name])
raise MyApp::ProfileNotFoundError if @profile.nil?
end
And add this to your `ApplicationController`:
:::ruby
rescue_from MyApp::ProfileNotFoundError, :with => :profile_not_found
Optionally, if you don't want to write that custom `profile_not_found` method, you may also supply a block:
:::ruby
rescue_from MyApp::ProfileNotFoundError do |exception|
render :nothing => "Profile not found.", :status => 404
end