I’ve seen many projects that have over 50 controllers in their main controllers directory. This makes finding related code very tedious. In this article I’ll show you a few tips how to organise your code into separate directories.
Namespaces are usually most common method to structure controllers. I’m sure you have seen or used /admin/* namespaces before. Its idea is to separate bigger parts of the application.
# config/routes.rb namespace :admin do resources :posts resources :categories end
Namespaces should be short and simple (e.g admin, advertising). Abbreviations are also allowed if they are understandable for the site visitors (e.g instead of writing human_resources_management, just use hrm).
The reason why we want namespaces to be short is to keep rails url helpers short. Here are few examples with the admin namespace:
form_for [:admin, Post.new] link_to "post link", [:admin, @post] link_to "post link", admin_post_path(@post)
Modules are meant for putting related code into separate directories without changing URLs nor url helpers. Lets say we have two different kinds of posts: drafts and published posts. They are related so we might want to put them in the same directory. We can put them into app/controllers/posts/ directory and add following routes:
# config/routes.rb scope :module => :posts do resources :drafts resources :published_posts end
Drafts controller itself might look something like this:
# app/controllers/posts/drafts_controller.rb module Posts class DraftsController < ApplicationController end end
Another benefit of using modules is that you can have two controllers with the same name. Lets say we have controllers ongoing_surveys and closed_surveys. Both of them have responders page. In the ongoing survey page you can add and remove responders, but in the closed survey page you can only see statuses of responders. Instead of making one responders controller and adding many conditionals we can separate these into two.
# config/routes.rb resources :ongoing_surveys do scope :module => :ongoing_surveys do resources :responders, :only => [:index, :create, :destroy] end end resources :closed_surveys do scope :module => :closed_surveys do resources :responders, :only => [:index] end end end
Now we have:
app/controllers/ongoing_surveys/responders_controller.rb app/controllers/closed_surveys/responders_controller.rb app/views/ongoing_surveys/responders/index.html.erb app/views/closed_surveys/responders/index.html.erb ...
Rails url helpers can be still used like there are no modules present. e.g
ongoing_survey_responders_path(@survey) polymorphic_path([@closed_survey, :responders]) # In the next post I'll show how to separate Survey into # ClosedSurvey and OngoingSurvey without inheritance.
Next time I’ll show you how to organise Rails models and how to avoid conflicts with Rails polymorphic url helpers.