DEV Community

Andy Leverenz
Andy Leverenz

Posted on • Originally published at web-crunch.com on

Custom Error Pages in Ruby on Rails

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)