Has Finder Functionality
It looks like Nick Kallen’s wildly popular has_finder plugin will be making its way into Rails 2.x in the form of named_scope. Observe:
class User < ActiveRecord::Base
named_scope :active, :conditions => {:active => true}
named_scope :inactive, :conditions => {:active => false}
named_scope :recent, lambda { { :conditions => ['created_at > ?', 1.week.ago] } }
end
# Standard usage
User.active # same as User.find(:all, :conditions => {:active => true})
User.inactive # same as User.find(:all, :conditions => {:active => false})
User.recent # same as User.find(:all, :conditions => ['created_at > ?', 1.week.ago])
# They're nest-able too!
User.active.recent
# same as:
# User.with_scope(:conditions => {:active => true}) do
# User.find(:all, :conditions => ['created_at > ?', 1.week.ago])
# end
All the goodness you’ve come to love in has_finder is now available as named_scope – plus you get some extra goodies too. User.all is given to you for free as an alias for User.find(:all).
Advanced
For those with more discriminating needs, don’t forget some of these has_finder tidbits:
Passing Arguments
Pass in arguments to your named scopes to specify conditions (or other props) at run-time.
class User < ActiveRecord::Base
named_scope :registered, lambda { |time_ago| { :conditions => ['created_at > ?', time_ago] }
end
User.registered 7.days.ago # same as User.find(:all, :conditions => ['created_at > ?', 7.days.ago])
Named Scope Extensions
Extend named scopes (in a similar fashion to association extensions).
class User < ActiveRecord::Base
named_scope :inactive, :conditions => {:active => false} do
def activate
each { |i| i.update_attribute(:active, true) }
end
end
end
# Re-activate all inactive users
User.inactive.activate
Anonymous Scopes
You can also pass around scopes as first class objects using scoped (a named scoped provided to you for free) as a way to build hairy queries on the fly.
# Store named scopes
active = User.scoped(:conditions => {:active => true})
recent = User.scoped(:conditions => ['created_at > ?', 7.days.ago])
# Which can be combined
recent_active = recent.active
# And operated upon
recent_active.each { |u| ... }
named_scope is a truly great feature. If you haven’t started using it yet, do so. You won’t know how you lived without it. Major thanks goes out to Nick.