+++ date = "2011-10-14" title = "Rails 3: Customized exception handling" tags = ["Rails", "rails3", "exceptions", "error", "rescue"] slug = "rails-3-customized-exception-handling" +++ 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 ```