Rails bundles default 404 (file not found), 422 (unprocessable entity),
and 500 (internal server error) pages into every newly generated
application. While they get the job done, these pages are pretty bland,
so in this post I’ll show you how to update them to suit the design of
your application. As an example, here’s what the default 404 page looks like:
If you open any Rails application lacking custom error pages, you’ll find this 404 page in the file public/404.html
.
Therefore the easiest possible solution to creating custom error pages
would be to simply edit each of these files as desired. Once updated,
you can view them in your development environment by navigating directly
to them (error pages aren’t shown by default in Rails’ development
environment when an error occurs; more on this later in the post). For
instance to see the custom 404 page you’d navigate to http://0.0.0.0:3000/404.html
.
While you could get away with directly modifying the 404.html
, 422.html
, and 500.html
pages, an alternative approach exists that provides more flexibility in
terms of how these errors are handled and eliminates the need to
potentially duplicate any layout markup that is otherwise automatically
injected into your views. Even better, this alternative approach is
accomplished in a few simple steps. Start by modifying your application.rb
file, adding the line config.exceptions_app = self.routes
. For instance here’s what the MyRailsApp config/application.rb
file looks like after adding this line:
module MyRailsApp
class Application < Rails::Application
config.exceptions_app = self.routes
end
end
This setting tells Rails to allow any exceptions to be handled by
another application, which is in this case the application router.
Next, add the following three lines to the bottom of your
config/routes.rb
file:
match '/404', to: 'errors#file_not_found', via: :all
match '/422', to: 'errors#unprocessable', via: :all
match '/500', to: 'errors#internal_server_error', via: :all
The
match
method is used to match a URL to one or more routes. It’s a bit more flexible than for instance the
get
method because you can configure it to be triggered in conjunction with
any matching route and HTTP method as opposed to for instance just a route matching the
get
method. You can pass specific HTTP methods into the
via
option, however we want to match routes in conjunction with any HTTP method, and so I’ve passed
all
into
via
.
Save these changes and next generate the
errors
controller and associated actions referenced in these newly created routes:
$ rails g controller Errors file_not_found unprocessable internal_server_error
Restart your Rails server, and navigate to some random nonexistent page. You’ll see that your development server
does not
respond as desired. This is because you need to tell Rails to no longer
dump detailed debugging information to the HTTP response, a feature
that is logically desired during the typical debugging process. You can
do this by adding the following line to your
config/environments/development.rb
file:
config.consider_all_requests_local = false
After having added this line, restart your Rails server again, navigate to a non-existent URL, and you should see the
file_not_found
default view!
With the dynamic error handlers implemented, you have the convenience of
allowing the default layout to be wrapped around the views, and can
optionally implement more advanced handlers. For instance you can take
advantage of various
request methods
to retrieve parts of the request (the requested page, parameters, etc)
and build in logic that suggests possible desirable destinations!