One of my Ruby on Rails apps has lots of models and a few models that each have lots of
has_many associations. For instance, the
Company model has 27
has_many associations. Naturally, I have routes and controllers for most of these associations, so it can be pretty overwhelming when you do an
ls in the
app/controllers directory. Unless you're intimately familiar with how all the models relate to each other, nothing will clue you in to the fact that a bunch of the controllers are for managing relations of
Company and that incoming requests reach those controllers via nested routes. This is because the default behavior of the Rails router is to point nested routes to a non-namespaced controller.
So, if you have routes defined like this:
resources :companies do resources :addresses end
/companies/1/address/2 will point to the
AddressesController, instead of, say, the
Companies::AddressesController. To me, this is confusing and unintuitive, but it is not a huge problem for smaller apps. It gets to be difficult once a routes file starts to look more like this:
resources :companies do resources :addresses resources :people resources :orders end resources :products resources :industries resources :salespeople
Now, when you look in your controllers directory, it will look like this:
# ls app/controllers addresses_controller.rb companies_controller.rb industries_controller.rb orders_controller.rb people_controller.rb products_controller.rb salespeople_controller.rb
To figure out that the
OrdersController all handle nested routes requires either 1) opening each one up and reading it, or 2) perusing the routes file. Essentially, the app's routes, which are hierarchical in nature, have been flattened into a single level of hierarchy. Okay, maybe you don't think it's that big of a deal, but imagine trying to make sense of this when you have dozens of controllers and many of them handle nested routes. Luckily, Rails has some tools to help organize your controllers.
What we really want to do is namespace all the controllers that handle nested routes for
Company associations in a module called
Companies. So, the
AddressesController from above would become the
Companies::AddressesController and so on. When we do this, because of the way Rails looks for classes we have defined in our app, we will end up with a
companies directory in
app/controllers that neatly contains all of our namespaced controllers.
Some code will explain this better. Here's how you tell the router that a set of routes should be directed to controllers namespaced under a certain module:
resources :companies do scope module: "companies" do resources :addresses resources :people resources :orders end end resources :products resources :industries resources :salespeople
And now, when you look in your controllers directory, it should look like this (with the
companies directory containing the namespaced controllers):
# ls app/controllers companies_controller.rb companies/ industries_controller.rb products_controller.rb salespeople_controller.rb
This is much more comprehensible. You know that all the controllers you see in the root controllers directory stand on their own, so to speak. And all the controllers in the
companies directory are for handling nested
Company routes (just remember to prefix the all of the controller class names with
Companies:: when you define them). Plus, now there is a shared hierarchy between your routes file, the names of your controller classes, and the names and layout of the files on disk.