William Notowidagdo Kiranatama Staff
Knowledge


The named_scope method, which was introduced since Rails 2.1, allows us to do finds in a more elegant and comfortable than it was in use also make the code that we make more DRY. By using named_scope we can apply certain conditions when we do find without having to write it repeatedly. For example, say I have a Book model that has the attribute published. To get a list of books already published, by just using the find I can write it like this
@books = Book.all(:conditions => ["published = ?", true])
By way as above, I will probably write it again and again if I want to use the @books on different controllers. We can avoid this by adding named_scope on Book model such as the following
class Book < ActiveRecord::Base
  named_scope :published_only, :conditions => ["published = ?", true]
end
so I can use it in the controller simply by invoke
@books = Book.published_only
of the code snippet above we can see that by using named_scope we have added a class method with the name published_only. Unlike Book.find, the object that is returned by Book.published_only is not an Array object but rather more like the association that was built by the has_many declaration. For example, we can invoke Book.published_only.first or Book.published_only.count. In addition we can also implementing Enumerable on the object that is returned by the named_scope, for example Book.published_only.each(&block). Named Scopes can also be called in sequence, for example we have one more named_scope
named_scope :hard_cover_only, :conditions => ["cover = ?", "hard"]
so that we can invoke
Book.published_only.hard_cover_only
Named Scopes are also available for has_many associations, eg
class Author > ActiveRecord::Base
  has_many :books
end
and
rowling = Author.find(221)
then rowling.published_only.hard_cover_only will return all books written by Rowling that have been published and has a hard cover. You can also pass in variable by using a lambda
class Book < ActiveRecord::Base
  named_scope :language, lambda { |language|
    { :conditions => { :language => language } }
  }
end
then Book.language('English') will return a list of English books.