Controller Inheritance in Rails
Published 11 July 05 by Justin French, 31 comments
Before we get started, I must completely credit Marten Veldthuis for pushing me in this direction way back in my first week with Rails.
A common pattern for me in most web applications I build is a separation of admin controllers into a separate “directory” (eg domain.com/admin/articles/).
For those of you who don’t know, you can generate Rails controllers that behave exactly like this, and they’ll work perfectly out-of-the-box with Routes:
Instead of script/generate controller articles (which would create a file controllers/articles_controller.rb), use script/generate controller admin/articles, which creates a file controllers/admin/articles_controller.rb.
So, moving along, I find that many of my admin controllers will share some common ground which gets repeated in each controller. Here’s some examples from something I’m working on:
before_filter :require_loginbefore_filter :require_sslbefore_filter :find_planlayout "admin_area"- etc
By default, all Rails controllers inherit from the ApplicationController. Here’s two examples:
class ArticlesController < ApplicationControllerclass Admin::ArticlesController < ApplicationController
What I like to do here is create a middle layer of inheritance, so that any common code and methods can be shifted out of the individual controllers and up to these middle layers.
So I create a new file controllers/admin_area_controller.rb with the following contents, moving the common code out of my individual controllers and into this middle layer.
class AdminAreaController < ApplicationController before_filter :require_login before_filter :require_ssl before_filter :find_plan layout "admin_area" end
I then change Admin::ArticlesController (controllers/admin/articles_controller.rb) to inherit from AdminAreaController instead of ApplicationController. Example:
class Admin::ArticlesController < AdminAreaController # my unique controller code here end
Just remember to change the inheritance of your new controllers after you generate them.
I also find that my regular controllers (which I call public controllers) share a lot of methods and filters, so I make a PublicAreaController just like the AdminAreaController, and make sure my public controllers inherit from it.
It may not seem worth the effort at first, but if you have 10 controllers all with the same 5 lines of code, that’s 10 places (and 50 lines of code) you have to remember to make changes to. By moving these into a middle layer, you reduce that to 1 place with 5 lines of code. It’s classic DRY (Don’t Repeat Yourself).
Need I say more?