December 11, 2006

Posted by John

Older: BDD and Setting Up Controllers

Newer: Speeding Up Prototype's $ Function

Pimping Find

Jamis Buck posted not too long ago about making active record finders work for you. In really simple applications, often times I have an admin and some general users. Annoyingly, I often do something like:

class ThingsController < ApplicationController
  before_filter :login_required
  
  def index
    @things = if current_user.admin?
      Things.find(:all)
    else
      current_user.things
    end
    
    # respond to the action here
  end
end

The approach I took on my last application, inspired by Jamis’ mods to #find looks like this:

class ThingsController < ApplicationController
  before_filter :login_required
  
  def index
    @things = Thing.find(current_user, :all)
    
    # respond to the action here
  end
end

Makes my controller a bit smaller and moves the logic to the model. It’s all possible by the following addition to my Thing model:

class Thing < ActiveRecord::Base
  class << self
    def find(*args)
      user = args.shift if args.first.is_a?(User)
      if user
        # go on like normal if user is admin otherwise scope things to the user passed in
        user.admin? ? super : user.things.find(*args) 
      else
        # go on like normal if no user passed in
        super
      end
    end
  end
end

Thing.find still works just like the original find method unless a user object is the first parameter. If so, it determines exactly which things the user passed in has access to and returns those. Anyone else have a better idea? This is working for me but I’d be open to any better solutions.

4 Comments

  1. I’d go with “@things = current_user.things” and extend the User model instead.

  2. I think I like that better. I’m not sure, I’ll have to try it out.

  3. Nathan de Vries Nathan de Vries

    Dec 12, 2006

    Yep, the definition of “all” is user specific so it makes logical sense for the rules to be defined within the User model.

  4. Another vote for moving this kind of thing to the User model, less brain twisty. (interesting blog btw!)

Sorry, comments are closed for this article to ease the burden of pruning spam.

About

Authored by John Nunemaker (Noo-neh-maker), a programmer who has fallen deeply in love with Ruby. Learn More.

Projects

Flipper
Release your software more often with fewer problems.
Flip your features.