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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
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.
1 2 3 4 5 |
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).
1 2 3 4 5 6 7 8 9 10 |
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.
1 2 3 4 5 6 7 8 9 |
# 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.
tags: ruby, rubyonrails

I’ve been waiting for this to get integrated – it’s fantastic, and will be a huge boon to Rails developers. Thanks for the update, Ryan!
This looks so incredibly useful. I’m relatively new to Rails and haven’t had a chance to play with the has_finder plugin, so I can’t wait to start using this.
Great. One of the first things I’m doing, when creating a new Rails project, is to install the has_finder plugin. I’m happy to hear that it has been merged into Rails now.
Thanks for the great post, Ryan. Will there be such a convenient shortcut for count specifically and rails statistics methods generally as well?
ex.User.count :conditions => { :active => true, :created_at.gt => 1.week.ago }Arie, yes – these methods are already supported just as they are with association extensions. E.g with my previous user example:
user.active.recent.count #=> 23or
user.active.recent.sum(:age) #=> 391Ryan,
That is really a bad example. As the conditions gets evaluated at load time, it’ll end up giving you inaccurate results in production where models get loaded only once.
Correct way would be :
Pratik – great point. I shall adjust my examples…
Really good feature… i like it very much… Thanks for the update Mr.Ryan…
Man, wish I would’ve found out about has_finder earlier! This is great!
I’m playing around with this right now, and I’m wondering how you would spec something like this out in RSpec if you were following a BDD approach? Or is this one of those things that is tested as part of rails, and I shouldn’t bother with? I would think that if you were using this to put together some complicated queries that there would have to be some sort of tests to ensure you are getting the results you want.
Very nice, just read about it on the official Rails Site. thanks for your examples! Daniel
It does not support other options supported by find like :include (but order is supported). Any idea about that?