Target: remove the
:controller/:action(/:id) routes from
Problem: make sure we have complete route coverage.
Well, the problem can be solved in two ways:
- Go into every controller and translate each action to a routing spec.
- Parse last week's logs and check whether each url is routable.
The first solution sounds easy but the second one sounds more fun. :-)
Remove the wildcard routes from
The offending lines look something like this:
match ':controller(/:action(/:id(.:format)))'. Get rid of them.
Get a few days' worth of
haproxy.log(or some other log):
Just ask your admin for that.
Take a random sample out of it:
cat ~/Logs/haproxy.log | shuf -n 1000 >> test/fixtures/logs/requests.logwill suffice.
Translate each url into a routing spec:
Use the following sample spec file and edit it to skip known failing urls and fix subdomains.
Run the routing specs:
bundle exec rspec spec/routing/from_log_routing_spec.rb
Write some proper routing specs for each logically failing url:
from_log_routeg_spec.rbonly tests that the urls are recognized. You need to write meaningful routing specs that test if the route links to the correct controller and action.
Fix routing errors in
After you have your proper routing specs in place, go and edit your
routes.rb. The reason we edit after we write specs is to make sure that the specs work as expected and the edit solved the failure.
Get a new random sample and repeat the rest of the recipe until happy.
Remember that Rails performs
PUT requests with an actual
POST with some
_method=delete. This means that the log will not always have the correct HTTP verb.
After deploy, what?
As always, things go wrong and your routing specs won't get you 100% coverage. If you use an exception_notification-type gem you might be fine, 404s will come flocking to your inbox. But...
If you are on Rails 3.0, the
RoutingError exceptions can't be rescued from inside of the application. A sane workaround I found looks like this:
match '*a', :to => 'statics#render_404'
Put this at the bottom of your routes (but inside the
route.draw block) and link it to an appropriate controller. The controller action should look something like this:
Good luck and good routings!