views:

45

answers:

2

I'm working on an application with quite a few related models and would like to hear some opinions on how best to organize the controllers.

Here are some options I have been considering:

1) Namespace the controllers. So, for example, have a controllers/admin directory and a controllers/public directory. This seems appealing for organization but also sorta contrived since a single resource could often have actions which might sensibly belong in different directories (e.g. the show action is public whereas the create action is admin). So this would mean breaking up some of my resources into two separate controllers - one public, one admin. Seems bad.

2) Create nested resources. I've only occasionally used nested resources so it's not always clear to me when it's best to nest resources versus simply passing the data you need through the params explicitly. Does anyone has some suggestions/examples of how best to use nested resources? When is it a good idea? When is it an overkill?

3) Just leave the default scaffolded controllers alone. Create new collection/member actions where needed and use before filters to set permissions within each controller. This seems most appealing since it keeps things simple upfront. But I'm sorta nervous about things getting messy down the line as some of the controllers might start to bloat with several new actions.

If anyone with experience designing large applications could offer some guidance here, it'd greatly appreciated.

+2  A: 

For organizing within our applications, I have done a little bit of everything depending on the situation.

First, regarding the separate controllers for admin/user functions, I will say that you probably don't want to go that route. We used authorization and before_filter to manage rights within the application. We rolled our own, but 20/20 hind-sight, we should have use CanCan. From there you can setup something like this (this is pseudo-code, actual language would depend on how you implemented authorization):

before_filter :can_edit_user, :only => [:new, :create, :edit, :update] #or :except => [:index, :show]

protected

def can_edit_user
  redirect_to never_never_land_path unless current_user.has_rights?('edit_user')
end

Or at a higher level

before_filter :require_admin, :only [:new, :create]

and in your application controller

def require_admin
  redirect_to never_never_land_path unless current_user.administrator?
end

It would depend which route, but I would use that for authorization instead of splitting up controllers.

As far as name spaces vs. Nested Resources, it depends on the situation. In several of our apps, we have both. We use name spaces when there is a cause for a logical separation or there will be shared functions between a group of controllers. Case and point for us is we put administrative functions within a namespace, and within we have users, roles and other proprietary admin functions.

map.namespace :admin do |admin|
  admin.resources :users
  admin.resources :roles
end

and then within those controllers we have a base controller, that stores our shared functions.

class Admin::Base < ApplicationController
  before_filter :require_admin
end

class Admin::UsersController < Admin::Base
  def new
   ....
end

This provides us logical separation of data and the ability to dry up our code a bit by sharing things like the before_filter.

We use nested controllers if there is going to be a section of code where you want some things to persist between controllers. The case from our application is our customers. We search for and load a customer and then within that customer, they have orders, tickets, locations. Within that area we have the customer loaded while we look at the different tabs.

map.resources :customers do |customer|
  customer.resources :tickets
  customer.resources :orders
  customer.resources :locations
end

and that gives us urls:

customers/:id
customers/:customer_id/orders/:id
customers/:customer_id/tickets/:id

Other advantages we have experienced from this is ease of setting up menu systems and tabs. These structures lend themselves well to an organized site.

I hope this helps!

Geoff Lanotte
Awesome. This is exactly what I needed. I especially like the idea of using namespaces and inheriting from a base controller. Also, I hadn't considered using CanCan but I'll definitely check it out. Thanks!
Cory Schires
A: 

Also, looks like nesting resources more than one level deep is almost certainly a bad idea:

http://weblog.jamisbuck.org/2007/2/5/nesting-resources

Yeah, it's a old article, but it makes a lot of sense to me.

If anyone disagrees, I'd like to hear why.

Cory Schires