origin: jerodsanto Blog
Since Rails 3 you’ve been able to configure an app to handle exceptions, which you want to point right at your router. To do this, add the following to config/application.rb:
module MyApp
class Application < Rails::Application
config.exceptions_app = self.routes
end
end
Make sure this is the last rule in config/routes.rb:
MyApp::Application.routes.draw do
get "*any", via: :all, to: "errors#not_found"
end
With this, any requested path — whatever the request type — that doesn’t match the previous routing rules will match this rule. The *any path starts with the * wildcard, so it will match anything. The any part is arbitrary, but you have to put something after the * to make it work. I’m sure there’s a good reason why, but somebody else will have to explain it.
class ErrorsController < ApplicationController
def not_found
respond_to do |format|
format.html { render status: 404 }
end
rescue ActionController::UnknownFormat
render status: 404, text: "nope"
end
end
You may be wondering why I suggest rescuing ActionController::UnknownFormat instead of adding a format.any block to handle any non-html request types. The problem with format.any is that it will only handle known mime types. This is a-okay for 404’ing .pngs, .json, .xml, etc., but it doesn’t handle the real crazy stuff, like wp-login.php. In other words, when it comes to catch-alls, ActionController::UnknownFormat has a bigger glove than format.any.
Create app/views/errors/not_found.html.erb and put your 404 page’s markup in there. This will use the application layout by default, so your 404 page will fit in with the rest of your site’s style.