Using named scopes (named_scope) in Ruby on Rails

Posted on 17 February 2010

Ruby on Rails 2.1 introduced the notion of a Named Scope. For me it's easily been one of the most beneficial features in helping to keep my code 'DRY'.

Essentially it allows you to apply conditions that you want to use when finding records without having to write out those conditions each time.

For example, I have an Article model and one of the attributes for an article is 'published'. Now in the old days I might have written code in my controller that looked something like this...

@articles = Article.find(:all, :conditions => ["published = ?", true])

I would have repeated this every time I wanted to get all the published articles out. The problem with this approach being that if what determines if an article is 'published' changes, then I'd need to go and change it in x number of places I'd written that line.

Introducing named_scope. In the Article model I simply define a named scope with a name and then my conditions...

class Article < ActiveRecord::Base
  named_scope :published, :conditions => ["published = ?", true]
end

Now in my controllers I can use...

@articles = Article.published

So much better, it's clearer, it's quicker to type and I can now update that published method in one place, safe in the knowledge it will ripple throughout all my controllers.

I can also chain named scopes together...

class Article < ActiveRecord::Base
  named_scope :published, :conditions => ["published = ?", true]
  named_scope :has_comments, :conditions => ["comments_count > 0"]
end

@articles_with_comments = Article.published.with_comments

You can also pass in variables to named scopes by using a lambda...

class Article < ActiveRecord::Base
  named_scope :by_author, lambda { |author| { :conditions => ["author_id = ?", author.id] }}
end

@your_articles = Article.published.by_author(current_user)

That last example is probably unrealistic as it's more likely you would call it like so...

@articles = @author.articles.published

Note that you can still use the named scope even though you're grabbing the articles via an Author model instance.

You can also use named scopes to setup commonly used limits or orders.

class Article < ActiveRecord::Base
  named_scope :recent_limit, :limit => "5"
  named_scope :order_by_last_comment, :order => "last_comment_at DESC"
end

Comments left...

  • Nice article man. For a beginner I found it really useful.

    Joey at 27 Feb 10 at 18:43

  • Super helpful and easy to understand! You rock!

    Gabe at 28 Jun 10 at 17:23

  • This is an excellent, simple to understand description, sir. Thanks!

    Matthew McEachen at 25 Jul 10 at 12:26

Got something to say?