Watch Your Namespace

Posted June 30, 2006

I helped a client troubleshoot a small "gotcha" in his Rails app this evening. It's an odd problem he bumped into after refactoring a controller into a group of controllers -- a particularly spiffy feature of Rails. For example, if you have a controller (say, FooController) that's getting rather large and unwieldy, you can break it up into smaller controllers in a Foo namespace:

controllers/foo_controller.rb

.. becomes ..

controllers/foo/barcontroller.rb controllers/foo/zedcontroller.rb controllers/foo/quux_controller.rb

... and the controller class declaration changes from:

class FooController < ApplicationController

... to ...

class Foo::BarController < ApplicationController

... and so on for Foo::ZedController and Foo::QuuxController. Pretty handy! It should be noted that the controller routing changes as well, making Foo::BarController#myaction accessable as http://mysite.com/foo/bar/myaction.

So here's the gotcha: if you're refactoring a FooController, chances are that you also have a Foo model (models/foo.rb). The Foo model is declared as class Foo, which means you're suddenly mucking about in its namespace when you declare a controller as Foo::BarController. You're in trouble town with generic routing errors when you attempt to load http://mysite.com/foo/bar/my_action, and the way out isn't immediately apparent if you're not specifically looking for such collisions.

The solution is to change either the controller or model namespace to something else. Controllers are a bit more flexible than models when it comes to naming, so changing Foo::BarController to Foos::BarController and renaming the directory to controllers/foos/bar_controller.rb fixes the problem -- if you don't mind pluralized names.

comments powered by Disqus