Ruby on Rails ships with default error pages for more popular requests you might encounter including 404
, 500
, and 422
. Each request has an associated static HTML
page that lives inside every new Ruby on Rails app's public
directory.
There may come a time where those static pages are a bit cumbersome to work with or you want to add a little more flair to yours using assets that already exist in your app. The public folder by design lives outside of the bound of what Rails and serve so you will see that each html
page has embedded styles and content.
This works for basic error pages but in my own case I wanted to leverage Tailwind CSS that I was already using inside my application. We can do this in a few steps but that means tweaking some configuration and telling your app how to handle errors in a new custom way.
Start with a controller
Generating a new ErrorsController
that inherits from ApplicationController
is a good first step in creating your custom error pages. With this controller we can render specific statuses that will ultimately render the corresponding views instead of those html
templates in the public
directory.
$ rails g controller errors not_found internal_server_error
The command above generates the controller and views we need. It also creates a helper file, basic routing, and some test files. Note the new methods not_found
and internal_server_error
in the controller.
Within those, we can tell our app what to render as a response. Each method maps to a different response.
# app/controllers/errors_controller.rb
class ErrorsController < ApplicationController
def not_found
render status: 404
end
def internal_server_error
render status: 500
end
end
Configuring routes
While our controller is set up for success we still need to add the appropriate routing to handle our new error pages.
# config/routes.rb
Rails.application.routes.draw do
...
match "/404", to: "errors#not_found", via: :all
match "/500", to: "errors#internal_server_error", via: :all
...
end
Using the match
methods we can pass in a relative path to the request we passed down from the controller. If that path is matched in the request cycle we instruct our app to target the methods on our ErrorController
class. The via: :all
essentially means match all requests.
Adjusting our configuration
Even with our new controller and routes set up we still need to turn off the default way Rails will handle errors. You can append the following to your main application.rb
file.
module YourAppName
class Application < Rails::Application
config.load_defaults 6.0 # I'm using Rails 6 at the time of this article
config.exceptions_app = self.routes # Add this line
end
end
The main line we need to add is config.exceptions_app = self.routes
. This essentially bypasses the internal error logic and tells the application to head to config/routes.rb
for further instruction.
Testing things out locally
While the code we have so far should work in the production environment you might want to test it out locally. To do this you need to disable a configuration in config/environments/development.rb
first.
# config/environments/development.rb
Rails.application.configure do
# Show full error reports.
config.consider_all_requests_local = false
end
Look for the line config.consider_all_requests_local = true
and swap that to false
temporarily. At this point you should restart your server (rails server
) and proceed to some unknown URL on your app. I went to localhost:3000/asdf
for example.
You should now see the corresponding error view templates in your browser instead of those found in the public
folder. We can now use our app's styling (Tailwind CSS in my case) to edit and adjust the views within app/views/errors
.
Success!
Now that you have custom error templates you can proceed to style those to match the design of your application in a much more efficient way. This took a little set up and can be extended much further but I hope you found it useful.
Top comments (0)