Custom Ruby on Rails Error Pages
Normally, 404 and 500 error pages are static HTML files in the public directory of a Rails app. These are minimally-styled pages that don’t get the same treatment as the rest of the app. There are different options to render a custom error page in your Rails app. My option is for dynamic error pages.
Dynamic error pages
First Remove the static HTML error pages
$ rm public/{404,422,500}.html
Set your own application routes as Rails’ exception app
# config/environments/production.rb
config.exceptions_app = self.routes
Add some routes for each error type
# config/routes.rb
# Dynamic error pages
get "/404", to: "errors#not_found", :via => :all
get "/422", to: "errors#unacceptable", :via => :all
get "/500", to: "errors#internal_error", :via => :all
Create an ErrorsController. Take care to render JSON error responses also, so it is API friendly.
class ErrorsController < ApplicationController
before_action :set_status
def not_found
respond_to do |format|
format.html { render status: 404 }
format.json { render json: { error: "Resource not found" }, status: 404 }
end
end
def unacceptable
respond_to do |format|
format.html { render status: 422 }
format.json { render json: { error: "Params unacceptable" }, status: 422 }
end
end
def internal_error
respond_to do |format|
format.html { render status: 500 }
format.json { render json: { error: "Internal server error" }, status: 500 }
end
end
def set_status
@exception = env['action_dispatch.exception']
@status = ActionDispatch::ExceptionWrapper.new(env, @exception).status_code
@response = ActionDispatch::ExceptionWrapper.rescue_responses[@exception.class.name]
end
end
Create views for each error action
# app/views/errors/{internal_error,not_found,unacceptable}.html.erb
<!-- example app/views/errors/not_found.html.erb -->
<h1>Page not found</h1>
<p>Whoops we couldn’t find the page you were looking for!</p>
Dynamic error pages are not without fault however, you still need static pages as a fallback for when your application errors due to your hosting provider/PaaS having unexpected downtime or incase you bump into a long running database migration when deploying.
If you use heroku you can configure your maintenance and error pages by running the following command:
$ heroku config:set \
ERROR_PAGE_URL=//s3.amazonaws.com/<your_bucket>/your_error_page.html \
MAINTENANCE_PAGE_URL=//s3.amazonaws.com/<your_bucket>/your_maintenance_page.html
Drawbacks
If the error page has any error, users will have difficulty to interact with the app, and to see the error page. Rails recognizes this situation an avoid an infinite loop. As a last resort, Rails will display a simple plaintext error message:
500 Internal Server Error
If Rails has completely crashed. When a Rails application is proxied by a web server like Nginx, the web server can be configured to serve static files from public/
. Theoretically, if your Rails application completely crashed, Nginx could still serve a static error page, like public/500.html
.
But with dynamic error pages this is not possible. By definition, Rails has to be up and running in order for those error pages to be displayed. You’ll need a static error page for this scenario.
Auto-generating a static error page with Capistrano
Assuming you deploy using Capistrano 3, you can use Capistrano to also generate a static public/500.html
page whenever your application is deployed. With proper Nginix configuration, this error page can be served even in the unfortunate scenario when your Rails app is completely offline.
- Define a Capistrno task
task :generate_500_html do on roles(:web) do |host| public_500_html = File.join(release_path, "public/500.html") execute :curl, "-k", "https://#{host.hostname}/500", "> #{public_500_html}" end end after "deploy:published", :generate_500_html
This instructs Capistrano to request the
/500
route of your application and save the resulting HTML topublic/500.html
. This happens on every successful deploy. Now your app has a static 500 error page that looks just like your dymamic one, automatically!
https://mattbrictson.com/dynamic-rails-error-pages
https://pooreffort.com/blog/custom-rails-error-pages/
https://coderwall.com/p/whjmra/handling-exceptions-in-your-rails-application