Written August 8, 2014. Tagged Ruby on Rails.
This is what I did to get a custom 404 error page on Rails 4, without replacing the default 500 and 422 error pages.
There are other solutions where you just use the router as the exceptions app, but then you have to handle those other errors as well.
It's very much based on this Gist by Turadg Aleahmad, but with some cleanup and fixes.
Remove the default public/404.html
to avoid any collisions.
Modify these files like so:
# …
module NameOfMyApp
class Application < Rails::Application
# …
require Rails.root.join("lib/custom_public_exceptions")
config.exceptions_app = CustomPublicExceptions.new(Rails.public_path)
end
end
Rails.application.routes.draw do
match "/404" => "errors#error404", via: [ :get, :post, :patch, :delete ]
# …
end
Add these files:
class CustomPublicExceptions < ActionDispatch::PublicExceptions
def call(env)
status = env["PATH_INFO"][1..-1]
if status == "404"
Rails.application.routes.call(env)
else
super
end
end
end
class ErrorsController < ApplicationController
def error404
render status: :not_found
end
end
<p>Sorry! No such page!</p>
To see the page in development, just visit /404
.
If you see the default Rails 404 page, you probably forgot to remove public/404.html
.
If you want to make sure it actually works, change config/environments/development.rb
to say
# Do not commit!
config.consider_all_requests_local = false
instead of true
.
Just don't keep that value, since you'll get less helpful errors in development, and you'll also disable the /rails/info/properties
page with debug info.
I haven't been able to figure out a way to do production-style error handling in a single test, so I settled for this:
require "rails_helper"
describe "404 page" do
it "is customized" do
# Haven't been able to get the "show instead of exceptions" thing working in tests, but this at least makes sure the page can render correctly.
visit "/404"
expect(page.status_code).to eq 404
expect(page).to have_content("Sorry!")
end
end