I received a comment in a recent article, by someone who saw the default routes in my config/routes.rb example and suggested I remove them. Yes! This makes total sense from several angles.
Between RESTful routes and named routes, there’s no good reason not to explicitly name all of your routes. Also, you don’t get the goodness of say, “pets_path” or “pet_path(@pet)” if you just let the default routes handle PetsController for you. Finally, if you’re doing TDD (test-driven development) then why aren’t you testing your routes as well?
Route testing is easy, and the tests themselves run super fast. One app of mine has almost 600 routing assertions that run in just 2 seconds. It’s fun to watch the dots for your routing tests zoom across the screen! Let’s start by adding a test file to our system with the standard boilerplate:
# test/unit/routing_test.rb require 'test_helper' class RoutingTest < ActionController::TestCase end
We’ll start with some TestUnit basics before we get into how Shoulda can make life easier. There are three assertions to learn:
def test_generates_user_index
assert_generates '/users', :controller => 'users', :action => 'index'
end
def test_recognizes_user_index
assert_recognizes {:controller => 'users', :action => 'index'}, '/users'
end
def test_routes_user_index
assert_routing '/users', :controller => 'users', :action => 'index'
end
The first assertion, assert_generates, verifies that if url generators like url_for are passed this hash of controllers, actions and whatever else, the correct route (/users in this case) is generated. The next assertion, assert_recognizes, does just the opposite, ensuring that a route of /users end up calling the index action of the users controller. The third version (assert_routing) does both! It combines the two previous assertions into one, and this is what you’ll want most of the time.
Using Shoulda to DRY up your tests
Here are the above tests, in Shoulda form:
require 'test_helper'
class RoutingTest < ActiveSupport::TestCase
context "routing users" do
should "generate /users" do
assert_generates '/users', :controller => 'users', :action => 'index'
end
should "recognize users" do
assert_recognizes {:controller => 'users', :action => 'index'}, '/users'
end
should "generate and recognize users" do
assert_routing '/users', :controller => 'users', :action => 'index'
end
end
end
While these tests are simple, they’re not very DRY. Just imagine, you’ll need to have seven of these tests *just* for the most basic RESTful route. Instead, install my shoulda routing macros:
script/plugin install git@github.com:bellmyer/shoulda_routing_macros.git
Now here’s an example routing file:
# config/routes.rb
ActionController::Routing::Routes.draw do |map|
# a simple resource
map.resources :chickens
# a resource with extra actions
map.resources :users, :collection => {:thankyou => :get}, :member => {:profile => :get}
# nested resources
map.resources :owners do |owners|
owners.resources :pets
end
# singleton resource
map.resource :session
map.ltp_contact_link '/ltp/:code', :controller => 'ltp_contacts', :action => 'new'
end
And this is how easy they are to test:
# test/unit/routing_test.rb
require 'test_helper'
class RoutingTest < ActionController::TestCase
# simple
should_map_resources :chickens
# with extra actions
should_map_resources :users, :collection => {:thankyou => :get}, :member => {:profile => :get}
# nested
should_map_resources :owners
should_map_nested_resources :owners, :pets
# singleton
should_map_resource :session
end
There’s no longer a good excuse to use default routes, or not test your routes in detail. Enjoy!
Tags: developers, macros, Rails, routes, Ruby, ruby on rails, shoulda, Testing