P
A
B
C
A
S
Thoughts, links, pictures on music, food, wine, film, tech etc.

2009-08-30

I wrote this:

The HDAD Pattern for organising controllers in Rails

I've been following a really simple pattern for organising controllers in Rails lately and it's helped me to simplify my controllers and write code that's nice and specific to certain contexts. I refer to it as the "Home / Dashboard / Admin Dashboard" pattern.

The pattern basically follows from the question "Who's looking at this controller?" ... and typically there will be three main users: anonymous users, logged in users and admin users. Given that their concerns when using an app and the various resources in that app will all be different, the trick is to create three namespaces.

Basically, the first page that an anonymous user will see, and subsequently the map.root, will be a singleton resource "home" ... mapped to home_controller. Next, when a user logs in, they get their own area, within their own namespace, something like "my" and they get their logged in singleton resource "dashboard" ... mapped to dashboard_controller. Finally, an admin user will have the option to log in to an "/admin" area and their own dashboard.

Following this, I now have logical namespaces to put any further controllers. If, for example, I have a model named "Post", I put a posts_controller in each of the namespaces, "/", "/my" and "/admin". This leaves me with three distinct areas that have their own permissions, context and views. I find it a really neat way to keep my controllers lean within particular context. It also helps me to only write code specific to those contexts in views.

Here's the routes file that would make this happen:

ActionController::Routing::Routes.draw do |map|
  
  map.root :controller => "home", :action => "show"

  map.resources :posts
  
  # Logged in user routes
  map.namespace :my do |my|
    my.dashboard :controller => "dashboard", :action => "show"
    my.root :controller => "dashboard", :action => "show"
  end
  
  # Admin Routes
  map.namespace :admin do |admin|
    admin.dashboard :controller => "dashboard", :action => "show
    admin.root :controller => "dashboard", :action => "show"
    admin.resources :posts
  end
end

With the pattern, each of the posts_controllers only need to have actions and code specific to each context: eg. the anonymous one need only have index and show code, because anonymous users will never be updating posts.

On the flipside, the admin version can have full permissions, and the logged in user can have granular access control. Cool, clean separation of intent in each context.


 
Made by Paul Campbell. paul@rushedsunlight.com. Twitter. Github.