In larger Rails applications, it is common to move related models, controllers, and/or views into sub-directories. Once moved, those classes will no longer be automatically found by Rails’ autoloader. There are two solutions:

  1. Configure the autoloader to look in the new directories.

  2. Place the classes into a namespace (module) whose name maps to the directory name.

I want to focus on the second option here.

In Ruby, there are two main ways to define a class inside a module.

The “standard” way is to nest the class definition inside the module:

Nested Class Definition
module MyModule
class MyClass
# ...
end
end

The “shortcut” way is to use the :: notation:

Shortcut Class Definition
class MyModule::MyClass
# ...
end

Both of these approaches generally work, but they are not equivalent.

The main difference is related to constant lookup. In the standard method, the code in MyClass can refer to other names in MyModule without an explicit namespace qualifier; Ruby will be able to resolve those references. Using the shortcut method, those references will have to be prefixed with MyModule::, because Ruby will not look inside MyModule for those names.

This is explained very well by Conrad Irwin in his excellent post, Everything you ever wanted to know about constant lookup in Ruby. It is also covered quite elegantly by Avdi Grimm in Ruby Tapas Episode 158. This episode is only available to subscribers, though, so you may not be able to watch it.

For this reason alone, I recommend using the standard approach. However, there are other considerations as well.

In order to use the shortcut approach in Ruby (without Rails), MyModule must already be defined when this class definition is loaded. Otherwise, Ruby will raise a NameError because it doesn’t know what MyModule is. This is another strong argument in favor of the standard approach in plain Ruby. Rails blurs this situation a bit however, because the autoloader will sometimes define MyModule for you. More on that in a later post.

Speaking of the autoloader, we need to be sure that it will continue to find these nested classes using either type of definition. For a good overview of how the autoloader works, see urbanautomaton’s excellent blog post, Rails autoloading — how it works, and when it doesn’t. It turns out that there are no major concerns on this front; the autoloader handles both approaches just fine.

In my brief experience with Rails, I’ve seen more of the shortcut notation than the standard notation. I’ve even seen the following pattern when using single-table inheritance:

STI Anti-Pattern
# in app/models/vehicle.rb:
class Vehicle < ActiveRecord::Base
# ...
end
# in app/models/vehicle/car.rb:
class Vehicle::Car < Vehicle
# ...
end

The shortcut notation is hiding what’s really going on here: we’re defining a subclass of Vehicle as a nested class inside the Vehicle class. This is almost certainly not what was intended. Using the standard form of definition makes this much more obvious.

I’ve seen other code where the namespace and the base class are not the same class, but the namespace is another class in the system. Again, I suspect that this was not intentional, but the shortcut notation hid the problem.

For this example, I’d prefer one of the following solutions:

Better STI Approach
# in app/models/vehicle.rb
class Vehicle < ActiveRecord::Base
# ...
end
# in app/models/vehicles/car.rb - note the plural
module Vehicles
class Car < Vehicle
# ...
end
end
Another Better STI Approach
# in app/models/vehicles/vehicle.rb
module Vehicles
class Vehicle
# ...
end
end
# in app/models/vehicles/car.rb
module Vehicles
class Car < Vehicle
# ...
end
end

In this case, the base class is also nested in the namespace, so it ends up in the same directory as its subclasses, which is nice. Having to refer to it as Vehicles::Vehicle everywhere is a bit of a pain, though, especially in relations. It doesn’t affect the underlying database table name though, because enclosing modules are not considered when inferring table names.

The major downside to the standard approach to defining namespaced classes is that all of the code ends up indented an extra level for each level of namespace. This can be a bit ugly. It is possible to use the following pattern to get around that problem:

Unindented Standard Approach
module MyModule; class MyClass
# ...
end; end

This works, but is much less “scannable”. It’s surprising to see two definitions on one line. I think that having the extra indentation is more palatable than this technique.

In summary, I recommend that namespaced classes always be defined using the standard method in both Ruby and Rails apps. The shortcut approach invites problems with constant lookup, extra namespace prefixes, NameErrors in Ruby, and unintentional class nesting.