exception_handler

by richpeck

πŸ’£ CUSTOM ERROR PAGES πŸ’£ for Ruby on Rails β†’ Translate Ruby/Rails Exceptions Into Branded 4xx/5xx HT...

441 Stars 60 Forks Last release: about 2 years ago (v0.8.0.0) 1.2K Commits 2 Releases

Available items

No Items, yet!

The developer of this repository has not created any items for sale yet. Need a bug fixed? Help with integration? A different license? Create a request here:

Exception Handler

ExceptionHandler is presently the MOST POPULAR exceptions gem for CUSTOM Rails error pages.

With 290,000+ downloads, it is the *only* gem to provide custom 400/500 exception pages for Rails 5 & 6

Current 0.8.0.0 (August 2018)

Coverage Status

πŸ“ Introduction - ⚠️ Installation - πŸ”§ Configuration - ☎️ Support - ⭐ Changelog

πŸ“ Introduction


ExceptionHandler replaces Rails' default error pages with dynamic views.

It does this by injecting config.exceptions_app with our controller - allowing us to populate erroneous responses with our own HTML. To understand how this works, you need to appreciate how Rails handles errors:

Rails uses ActionDispatch::ShowExceptions (above) to generate error responses.

Because web browsers (Rails is a web framework) can only interpret HTTP responses, Ruby/Rails exceptions have to be translated into something a browser can read. This is done by calling the above middleware.

--

As highlighted, an HTTP response is built independent of the Rails stack. This includes assigning an HTTP status code and HTML response body. It's the response body which ExceptionHandler is designed to override.

⚠️ Installation


πŸ’Ž RubyGems (Code) | πŸ’» Medium (Tutorial)

# Gemfile
gem 'exception_handler', '~> 0.8.0.0'

Because ExceptionHandler is built around a Rails engine, there is nothing to be done to get it working in production. Installing the Gem should translate your production 4xx/5xx error pages into dynamic views.

Environments other than production (development/staging) required the dev variable to be true.

πŸ”§ Configuration


πŸ“ Config    πŸ’» Dev    πŸ’Ύ Database    βœ‰οΈ Email    πŸ‘“ Views    πŸ’¬ Locales    πŸ“‹ Layouts    β›”️ Custom Exceptions


The ONLY thing you need to manage

ExceptionHandler
is its
config
settings.

Whilst the gem works out of the box (without any configuration), if you want to manage the

layouts
,
email
,
dev
or the
database
, you'll need to set the appropriate values in the config hash.

This is done in

config/application.rb
or
config/environments/[env].rb
↴
# config/application.rb

module YourApp class Application < Rails::Application

# =&gt; This is an example of ALL available config options
# =&gt; You're able to see exactly how it works here:
# =&gt; https://github.com/richpeck/exception_handler/blob/master/lib/exception_handler/config.rb

# =&gt; Config hash (no initializer required)
config.exception_handler = {
  dev:        nil, # allows you to turn ExceptionHandler "on" in development
  db:         nil, # allocates a "table name" into which exceptions are saved (defaults to nil)
  email:      nil, # sends exception emails to a listed email (string // "[email protected]")

  # Custom Exceptions
  custom_exceptions: {
    #'ActionController::RoutingError' =&gt; :not_found # =&gt; example
  },

  # On default 5xx error page, social media links included
  social: {        
    facebook: nil, # Facebook page name   
    twitter:  nil, # Twitter handle  
    youtube:  nil, # Youtube channel name / ID
    linkedin: nil, # LinkedIn name
    fusion:   nil  # FL Fusion handle
  },  

  # This is an entirely NEW structure for the "layouts" area
  # You're able to define layouts, notifications etc ↴

  # All keys interpolated as strings, so you can use symbols, strings or integers where necessary
  exceptions: {

    :all =&gt; {
      layout: "exception", # define layout
      notification: true, # (false by default)
      deliver: #something here to control the type of response
    },
    :4xx =&gt; {
      layout: nil, # define layout
      notification: true, # (false by default)
      deliver: #something here to control the type of response    
    },    
    :5xx =&gt; {
      layout: "exception", # define layout
      notification: true, # (false by default)
      deliver: #something here to control the type of response    
    },
    500 =&gt; {
      layout: "exception", # define layout
      notification: true, # (false by default)
      deliver: #something here to control the type of response    
    },

    # This is the old structure
    # Still works but will be deprecated in future versions

    501 =&gt; "exception",
    502 =&gt; "exception",
    503 =&gt; "exception",
    504 =&gt; "exception",
    505 =&gt; "exception",
    507 =&gt; "exception",
    510 =&gt; "exception"

  }
}

end end

For a full retinue of the available options, you'll be best looking at the

config
file itself.

--

If using an

engine
, you DON'T need an
initializer
: ```rb

lib/engine.rb

module YourModule class Engine < Rails::Engine

# => ExceptionHandler
# => Works in and out of an initializer
config.exception_handler = {
  dev: nil, # => this will not load the gem in development
  db:  true # => this will use the :errors table to store exceptions
}

end end ```

The best thing about using a

config
options block is that you are able to only define the options that you require.

If you have particular options you only wish to run in

staging
, or have single options for
production
etc, this setup gives you the ability to manage it properly...
πŸ’» Dev

As explained,

ExceptionHandler
does not work in
development
by default.

This is because it overrides the

exceptions_app
middleware hook - which is only invoked in
production
or
staging
.

To get it working in

development
, you need to override the
config.consider_all_requests_local
setting (a standard component of Rails) - setting it to "false" ↴

This is normally done by changing the setting in your Rails config files. However, to make the process simpler for

ExceptionHandler
- we've added a
dev
option which allows you to override the hook through the context of the gem...
# config/application.rb
config.exception_handler = { dev: true }

This disables

config.consider_all_requests_local
, making Rails behave as it would in production.

Whilst simple, it's not recommended for extended use. Very good for testing new ideas etc.


πŸ’Ύ DB

To save exceptions to your database, you're able to set the

db
option.

Because we use a

controller
to manage the underlying way the system works, we're able to invoke the likes of a
model
with other functionality.

Ths is done automatically with the latest version of

ExceptionHandler
.

To do this, once you've populated the option with either

true
or a
string
, run
rails db:migrate
from your console.

Our new

migration system
will automatically run the migration.

# config/application.rb
config.exception_handler = { db: true }

This enables

ActiveRecord::Base
on the
Exception
class, allowing us to save to the database.

In order for this to work, your db needs the correct table.


βœ‰οΈ Email

ExceptionHandler
also sends email notifications.

If you want to receive emails whenever your application raises an error, you can do so by adding your email to the config:

# config/application.rb
config.exception_handler = {
  email: "[email protected]"
}

Please Note this requires

ActionMailer
. If you don't have any outbound SMTP server,
SendGrid
is free.

From version

0.8.0.0
, you're able to define whether email notifications are sent on a per-error basis:

# config/application.rb
config.exception_handlder = {

This has to be present for any "notification" declarations to work

Defaults to 'false'

email: "[email protected]",

Each status code in the new "exceptions" block allows us to define whether email notifications are sent

exceptions: { :all => { notification: true }, :50x => { notification: false }, 500 => { notification: false } } }


πŸ‘“ Views

What most people want out of the view is to change the way it looks. This can be done without changing the "view" itself.

To better explain, if

ExceptionsController
is invoked (by

exceptions_app
), it has ONE method (
show
).

This method calls the

show
view, which is entirely dependent on the locales for content & the layout for the look.

This means that if you wish to change how the view "looks" - you're either going to want to change your layout or the locales. There is NO reason to change the

show
view itself - it's succinct and entirely modular. Whilst you're definitely at liberty to change it, you'll just be making the issue more complicated than it needs to be.

--

We've also included a number of routes which shows in

dev
mode (allowing you to test):


πŸ’¬ Locales

Locales are used to create interchangeable text (translations/internationalization).

--

In

ExceptionHandler
, it provides the wording for each type of error code.

By default, the English name of the error is used (

"404"
will appear as
"Not Found"
) - if you want to create custom messages, you're able to do so by referencing the error's "status_code" within your locales file:
# config/locales/en.yml
en:
  exception_handler:
    not_found:              "Your message here" # -> 404 page
    unauthorized:           "You need to login to continue"
    internal_server_error:  "This is a test to show the %{status} of the error"

You get access to

%{message}
and
%{status}
, both inferring from an
@exception
object we invoke in the controller...

  • %{message}
    is the error's actual message ("XYZ file could not be shown")
  • %{status}
    is the error's status code ("Internal Server Error")

--

By default, only

internal_server_error
is customized by the gem:
# config/locales/en.yml
en:
  exception_handler:
    internal_server_error: "%{status} Error %{message}"

πŸ“‹ Layouts

The most attractive feature of

ExceptionHandler
(for most) is its ability to manage
layouts
for HTTP status.

--

The reason for this is due to the way in which Rails works β†’ the "layout" is a "wrapper" for the returned HTML (the "styling" of a page). If you have no layout, it will render the "view" HTML and nothing else.

This means if you want to change the "look" of a Rails action, you simply have to be able to change the

layout
. You should not change the view at all.

To this end,

ExceptionHandler
has been designed around providing a SINGLE VIEW for exceptions. This view does not need to change (although you're welcome to use a
generator
to do so) - the key is the
layout
that's assigned...
  • 4xx
    errors are given a
    nil
    layout (by default) (inherits from
    ApplicationController
    in your main app)
  • 5xx
    errors are assigned our own
    exception
    layout:
# config/application.rb
config.exception_handler = {

The new syntax allows us to assign different values to each HTTP status code

At the moment, only 'layout' & 'notification' are supported

We plan to include several more in the future...

exceptions: { all: { layout: nil } # -> this will inherit from ApplicationController's layout } }

The

layout
system has changed between
0.7.7.0
and
0.8.0.0
.

Building on the former's adoption of HTTP status-centric layouts, it is now the case that we have the

all
,
5xx
and
4xx
options - allowing us to manage the layouts for blocks of HTTP errors respectively:
# config/application.rb
config.exception_handler = {

Old (still works)

No "all" / "4xx"/"5xx" options

layouts: { 500 => 'exception', 501 => 'exception' },

New

exceptions: { :all => { layout: 'exception' }, :4xx => { layout: 'exception' }, :5xx => { layout: 'exception' }, # -> this overrides the :all declaration 500 => { layout: nil } # -> this overrides the 5xx declaration } }

We've bundled the

exception
layout for

5xx
errors because since these denote internal server errors, it's best to isolate the view system as much as possible. Whilst you're at liberty to change it, we've found it sufficient for most use-cases.
⛔️ Custom Exceptions

As mentioned, Rails' primary role is to convert Ruby exceptions into HTTP errors.

Part of this process involves mapping Ruby/Rails exceptions to the equivalent HTTP status code.

This is done with

config.action_dispatch.rescue_responses
.

Whilst this works well, it may be the case that you want to map your own classes to an HTTP status code (default is

Internal Server Error
).

If you wanted to keep this functionality inside

ExceptionHandler
, you're able to do it as follows:
# config/application.rb
config.exception_handler = {
  custom_exceptions: {
    'CustomClass::Exception' => :not_found
  }
}

Alternatively, you're able to still do it with the default Rails behaviour:

# config/application.rb
config.action_dispatch.rescue_responses = { 'CustomClass::Exception' => :not_found }

πŸ’Ό Generators

If you want to edit the

controller
,
views
,
model
or
assets
, you're able to invoke them in your own application.

This is done - as with other gems - with a single

generator
which takes a series of arguments:

rails g exception_handler:views
rails g exception_handler:views -v views
rails g exception_handler:views -v controllers
rails g exception_handler:views -v models
rails g exception_handler:views -v assets
rails g exception_handler:views -v views controllers models assets

If you don't include any switches, this will copy all

ExceptionHandler
's folders put into your app.

Each switch defines which folders you want (EG

-v views
will only copy
views
dir).
βœ”οΈ Migrations

You DON'T need to generate a migration anymore.

From

0.7.5
, the

migration
generator has been removed in favour of our own migration system.

The reason we did this was so not to pollute your migrations folder with a worthless file. Our migration doesn't need to be changed - we only have to get it into the database and the gem takes care of the rest...

If you set the

db
option in config, run

rails db:migrate
and the migration will be run.

To rollback, use the following:

rails db:migrate:down VERSION=000000

The drawback to this is that if you remove

ExceptionHandler
before you rollback the migration, it won't exist anymore.

You can only fire the

rollback
when you have
ExceptionHandler
installed.

☎️ Support


You're welcome to contact me directly at [email protected].

Alternatively, you may wish to post on our GitHub Issues, or StackOverflow.

--

Medium

⭐ Changelog


1.0.0.0 - [ ] TBA

0.8.0.0 - [x] README (focus on utility) - [x] Introduction of

4xx
,
5xx
,
:all
for layouts config - [x] Changed
layouts
to
exceptions
in config
- [x] Email improvement - [x] Streamlined migration - [x] Updated model

0.7.7.0 - [x] HTTP status layouts

0.7.0.0 - [x] Wildcard mime types - [x] Custom exceptions - [x] Test suite integration - [x] Model backend - [x] Sprockets 4+ - [x] New layout - [x] Readme / wiki overhaul

0.6.5.0 - [x] Streamlined interface - [x] ActiveRecord / Middleware overhaul - [x] Supports Sprockets 4+ (

manifest.js
) - [x] Email integration - [x] Asset overhaul & improvement - [x] Removed dependencies

0.5.0.0 - [x] Locales - [x] Email notifications - [x] Full test suite - [x] Rails 4.2 & Rails 5.0 native (

request.env
fix) - [x] Controller fixed - [x]

DB
fixed - [x] Legacy initializer support (more) - [x] Rails asset management improvement - [x] Reduced gem file size

0.4.7.0 - [x] New config system - [x] Fixed controller layout issues - [x] Streamlined middleware - [x] New layout & interface

<!-- Sep -->

404 + 500 Errors

ExceptionHandler provides custom error pages gem for Rails 5+
No other gem is as simple or effective at providing branded exception pages in production

Coverage Status

➑️ Download & Info ⬅️

<!-- Sep -->

:copyright:

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.