Earlier today @alan_meier pointed out that in certain circumstances, my post on dynamic error pages leads to unexpected results: namely, though most errors are caught, 404s are not. I didn’t experience this myself because most 404s, for me, result in an ActiveRecord::RecordNotFound error, since my application has a wildcard route at the very end. But if you don’t then my post on dynamic error pages won’t work for you very well. Here, then, is an explanation of the problem and how to fix it.
The Problem
Summarized elegantly here:
In Rails 2.3.x, one is able to stick this in ApplicationController to present the user with a custom 404 screen:
rescue_from(ActionController::RoutingError) { render :text => 'This is a custom 404.' }
Now in Rails 3, because routing is done as middleware (ActionDispatch), it seems that the ActionController::RoutingError that gets thrown by ActionDispatch no longer can be caught from ApplicationController – the error is already thrown and ActionDispatch renders /templates/rescues/routing_error.erb before the controller can rescue_from the error.
Essentially, rescue_from ActionController::RoutingError
is never rescued because it’s raised in Rack, not the application itself.
The Solution
Requires a couple changes on our parts. First, let’s change our application_controller.rb:
1 2 3 4 5 6 7 |
|
So far, just as usual. Now we define the actual actions:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
Since we’re going to be exposing render_404
as an action, now, we have to make parameters into it optional: but we know that if render_exception
doesn’t receive an exception, it actually got a 404.
Finally, we need to add a globbed, wildcard route at the conclusion of our routes.rb. But if we just add one in, then engines and Gems that also rely on wildcard routes will fail. The solution is to do this through our application.rb, like so:
1 2 3 4 5 6 7 8 9 10 |
|
Now it won’t punch any Gem or engine routes, but will still redirect 404s correctly to our render_404 action.
Thanks to @alan_meier for bringing this problem to my attention, and I hope this correction helps some people out!