Pimping Find
December 11th, 2006
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.

December 11th, 2006 at 06:39 PM
I’d go with ”@things = current_user.things” and extend the User model instead.
December 11th, 2006 at 07:02 PM
I think I like that better. I’m not sure, I’ll have to try it out.
December 12th, 2006 at 12:52 AM
Yep, the definition of “all” is user specific so it makes logical sense for the rules to be defined within the User model.
December 14th, 2006 at 01:06 PM
Another vote for moving this kind of thing to the User model, less brain twisty. (interesting blog btw!)