gaffe
Gaffe makes having customized error pages in Rails applications an easy thing.
It takes advantage of a feature present in Rails 3.2+ called exceptions_app.


It comes with default error pages but makes it very easy to override them (which you should do). The default error pages look like this:

Installation

Add this line to your application’s Gemfile:

gem 'gaffe'

Usage

The easiest way to use Gaffe is with an initializer:

# config/initializers/gaffe.rb
Gaffe.enable!

Custom controller

However, if you want to use your own controller:

# config/initializers/gaffe.rb
Gaffe.configure do |config|
  config.errors_controller = ErrorsController
end

Gaffe.enable!

It’s also possible to use a custom controller based on the URL in which the error has occured. This is especially useful if you have an application that also serves API requests via JSON. You would probably want to serve API errors through JSON and regular errors through HTML pages.

# config/initializers/gaffe.rb
Gaffe.configure do |config|
  config.errors_controller = {
    %r[^/api/] => Api::ErrorsController,
    %r[^/] => ErrorsController
  }
end

Gaffe.enable!

The only required thing to do in your custom controller is to include the Gaffe::Errors module.

Only show will be called so you might want to override it. If you don’t override it, Gaffe will try to render the view "errors/#{@rescue_response}" within your application (or use its default error page if the view doesn’t exist).

You might also want to get rid of filters and other stuff to make sure that error pages are always accessible.

class ErrorsController < ApplicationController
  include Gaffe::Errors
  skip_before_filter :ensure_current_user

  def show
    # The following variables are available:
    @exception # The encountered exception (Eg. `#<ActiveRecord::NotFound …>`)
    @status_code # The status code we should return (Eg. `404`)
    @rescue_response # The "standard" name for the status code (Eg. `:not_found`)
  end
end

For example, you might want your Api::ErrorsController to return a standard JSON response:

class Api::ErrorsController < Api::ApplicationController
  include Gaffe::Errors
  skip_before_filter :ensure_current_user

  def show
    render json: { error: @rescue_response }, status: @status_code
  end
end

Custom views

You can (and should!) also use your own views. You just have to create a layout:

<!-- app/views/layouts/error.html.erb -->
<h1>Error!</h1>
<%= yield %>

And create a different view for each possible error rescue response (rails reference). For example, for 404 errors:

<!-- app/views/errors/not_found.html.erb -->
<p>This page does not exist.</p>

Custom exceptions

If your application is raising custom exceptions (through gems or your code) and you want to render specific views when it happens, you can map them to specific rescue responses.

# config/application.rb
config.action_dispatch.rescue_responses.merge! 'CanCan::AccessDenied' => :forbidden
config.action_dispatch.rescue_responses.merge! 'MyCustomException' => :not_acceptable

Rails development mode

Rails prefers to render its own debug-friendly errors in the development environment, which is totally understandable. However, if you want to test Gaffe’s behavior in development you’ll have to edit the config/environments/development.rb file.

# Make Rails use `exceptions_app` in development
config.consider_all_requests_local = false

License

Gaffe is © 2013 Mirego and may be freely distributed under the New BSD license. See the LICENSE.md file.

The mushroom cloud logo is based on this lovely icon by Gokce Ozan, from The Noun Project. Used under a Creative Commons BY 3.0 license.

About Mirego

Mirego is a team of passionate people who believe that work is a place where you can innovate and have fun. We proudly build mobile applications for iPhone, iPad, Android, Blackberry, Windows Phone and Windows 8 in beautiful Quebec City.

We also love open-source software and we try to extract as much code as possible from our projects to give back to the community.