By default, Rails will render
public/404.html (with a 404 status in the header) when it thinks an error 404 is appropriate.
Why use a custom action?
For error 500 (Internal Server Error) pages, rendering a static file makes sense. If your app is broken enough to give that error, it may not be up to the task of rendering a dynamic error page.
But for 404 pages, a dynamic template might be preferable. You can use your site layouts (though some would argue error pages should look distinctly different) and helpers, you can suggest alternative content or try to figure out where they wanted to go, and so on.
Note that even when your 404 page is a static HTML file, it is still rendered by Rails (after failing to match a route, or some other error), so replacing it with a dynamic action adds less overhead than you might assume.
Old school: Overriding
Blog posts on the subject that I found (like this one) suggest overriding
If you go that route (or a similar one using the new-fangled
rescue_from), these are the errors that Rails by default would render
ActionController::RoutingError ActionController::UnknownAction ActiveRecord::RecordNotFound
They are enumerated in
New school: Change it at the source
I wanted to know exactly when Rails was rendering
public/404.html, not just rescue some exceptions that I had noticed led to a 404 in production, so I dug into the code – hence the list above.
Rather than defining my own
ApplicationController, where I would have to duplicate the list of exceptions that should cause a 404, I defined my own
1 2 3 4 5 6 7
render_404 method can look something like
1 2 3 4 5 6 7
render_optional_error_file is a documented method, so even though using
rescue_action is probably less likely to break with future versions of Rails, I should think this solution is reasonably reliable.
Note that you won’t see this in local development, since it involves
rescue_action_in_public. If you want to have a look, put
ApplicationController, but don’t forget to remove it after.
Another caveat is that if your server configuration has a directive like
ErrorDocument 404 /404.html (Apache) or
error_page 404 /404.html; (nginx), that will eclipse your Rails action. Just remove the directive.