Extend has_many with the :extend option
The method has_many has several options that help you refine an association. The :extend option is one that I found myself using recently, and thought it would be nice to share with the internet.
Say you have a Friendship class that belongs to a User class, and that your User class has_many :friends, :through => :friendships. A good old fashioned @user.friends would return all the user records for @user’s friends.
Let’s also say your friendships table contains the fields user_id:integer, friend_id:integer, and state:string, where state can either be ‘active’, ‘requested’, or ‘pending’.
You might be tempted to do something like this in your User class:
has_many :friends do
def active
...some query...
end
...and so on for each state
end
I suppose, this would be fine if you only needed one method. You need something for each state, though, and this direction leads to unsightliness quite fast. Enter :extend.
Using this method, you can define methods in a module and call that module using extend. So the association looks like this:
has_many :friends, :through => :friendships, :extend => FriendshipState
FriendshipState is the module where your methods are defined:
module FriendshipState
Order = "users.last_name asc, users.first_name desc"
def pending
find(:all, :conditions => ['friendships.state = ?', 'pending'], : order => Order)
end
def requested
find(:all, :conditions => ['friendships.state = ?','requested'], : order => Order)
end
def active
find(:all, :conditions => ['friendships.state = ?','active'], : order => Order)
end
end
NOTE: there should be no space between ‘:’ and ‘order’. I did that to prevent god forsaken emoticons
The join is handled for you, so @user.friends.active returns all user records for @user’s active friendships; and so on with pending and requested.
SELECT `users`.* FROM `users` INNER JOIN `friendships` ON `users`.id = `friendships`.friend_id WHERE ((`friendships`.user_id = 1) AND (friendships.state = 'active')) ORDER BY users.last_name asc, users.first_name desc
Nice, huh?
Quick disclaimer, I’m no command line guru, but I am a huge fan of anything that helps me do my job faster, so I decided to load up some aliases in .bashrc this morning. A perfectly good Sunday morning activity.



“New Year” blog posts typically deal with lists. Lists of the best and worst of the preceeding year. This post will be no different. Observe
I'm Eric Hurst, and I make the Internet from a comfy chair in Kansas City. Send an email to "eric at erichurst dot com" (spam is bad) to hire me.
