Skip to content

Instantly share code, notes, and snippets.

@joshuaclayton
Created August 14, 2008 15:04
Show Gist options
  • Save joshuaclayton/5439 to your computer and use it in GitHub Desktop.
Save joshuaclayton/5439 to your computer and use it in GitHub Desktop.
# This is useful if you need to get a subclassed model through a has_many :through association
# Just iterate through each user type you want available and create a named_scope. It sounds
# repetitive since you can just call Subclass.all to return those results, but if it's a
# :through association, it becomes harder to grab
#
# For example, let's say I've got a handful of different user subclasses, and I've got
# magazines and subscriptions. I want to, on a subscription, find all users of a certain
# subclass. Adding named scopes to a user is much easier than iterating through the array to
# find all users whose type matches whichever.
#
# For example, the 'old' way to grab a subclass:
# Magazine.first.users.find_all {|u| u.is_a?(Client) }
#
# The more correct way would be to do something like this:
# Magazine.first.users.clients
#
# This would then use SQL to generate the filter instead of relying on Ruby's iterators to return
# results (which is obviously a lot faster, especially if the type column is indexed (which it
# should be) and your result sets are large. Plus, it reads a lot better.
#
# And although you could potentially put this on the Magazine model, it then makes the Magazine
# model much too intimate with the types of users. Bad form.
class User < ActiveRecord::Base
TYPES = %w(Admin Manager Client).freeze
User::TYPES.each do |type|
class_eval <<-EOV
named_scope :#{type.tableize}, :conditions => ["users.user_type = ?", "#{type}"]
EOV
end
has_many :subscriptions
has_many :magazines, :through => :subscriptions
end
class Subscription < ActiveRecord::Base
belongs_to :user
belongs_to :magazine
end
class Magazine < ActiveRecord::Base
has_many :subscriptions
has_many :users, :through => :subscriptions
# possible (but bad) way to grab user types, since any :through association would need all these (and it's not DRY
# has_many :clients, :through => :subscriptions, :source => :user, :conditions => "user_type = 'Client'"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment