views:

63

answers:

1

I'm currently writing a Rails app, and hit a somewhat strange quirk. I have a controller PermissionsController, which is mainly for display purposes at the moment. So my routing is locked down:

map.resources :permissions, :only => [:index, :show]

Unfortunately, when writing the tests, one of the routing tests fails:

it "does not recognize #new" do
  { :get => "/permissions/new" }.should_not be_routable
end

with the error:

Expected 'GET /permissions/new' to fail, but it routed to
{"action"=>"show", "id"=>"new", "controller"=>"permissions"} instead

Obviously, the #show action's route is matching with /permissions/:id, which also gives the expected error Couldn't find Permission with ID=new if you actually browse to that URL.

This is not a serious error, as it is correctly raising an exception with the bad :id parameter, but it's kind of ugly. Is there any way to actually make Rails reject that route? Some trick in the routing options that I'm missing?

I suppose I should just leave that test out and ignore it, or maybe remove the whole RESTful idea altogether and go back to a simpler map.connect 'permissions/:id' style. I strongly suspect I'll be expanding this in the future, though, and kind of wanted to keep my controllers consistent with each other. Just having to add occasional :only or :except rules made routes.rb nice and clean...

A: 

Well it is mapping correctly as you point out. If you want to ensure that :id is always a number then you would not have this problem.

This can be done with a requirement on the route.

map.connect ':controller/:action/:id', :requirements => { :id => /\d?/ }
map.connect ':controller/:action/:id.:format', :requirements => { :id => /\d?/ }
Will