Rails & named_scope

Tháng Năm 18, 2009

Source: http://mattpayne.ca/blog/post/named-scope

Lately everyone has been going mad over a relatively new addition to rails: named_scope. Up until now, I hadn’t had the chance to try it out. I always just assumed that it was more syntactic fluff that seems to accumulate. Wow, was I wrong! It’s an unbelievably cool and useful idea. Here’s a really simple example. Say I have 2 models: Country and Region. They are as you would expect. A Region belongs to a Country and a Country has many Regions, etc. I use them pretty much for dropdown lists and things like that. Here’s some code:

  1. class Region < ActiveRecord::Base
  2. belongs_to :country
  3. end
  4. class Country < ActiveRecord::Base
  5. has_many :regions
  6. end

Prior to named_scope, if you wanted to get all Regions in alphabetical order (as an example), you’d have to do something like:

  1. class Region < ActiveRecord::Base
  2. #other code
  3. def self.ordered
  4. find(:all, :order => “name ASC”)
  5. end
  6. end

Which was ok, but this is nicer:

  1. class Region < ActiveRecord::Base
  2. named_scope :ordered, :order => “name ASC”
  3. #other code
  4. end

This creates a method on the Region class called ordered that can simply be called.

OK, so that’s cool and all, but really not that big a deal, right? Well, no – until you consider that you can chain calls to named_scope, thus adding more and more constraints. For example:

  1. class Region < ActiveRecord::Base
  2. belongs_to :country
  3. named_scope :ordered, :order => “name ASC”
  4. named_scope :by_country, lambda { |c| { :conditions => [“country_id = ?”, c.id] } }
  5. named_scope :containing, lambda { |s| { :conditions => [“name like ?”, “%#{s}%”] } }
  6. end
  7. class Runner
  8. c = Country.find_by_name(“Canada”)
  9. regions = Region.by_country(c).containing(“A”).ordered
  10. puts “Provinces in Canada containing the letter A in ascending order: #{regions.inspect}”
  11. end

This generates SQL that looks like this:

SELECT * FROM `regions` WHERE ((name like ‘%A%’) AND (country_id = 1)) ORDER BY name ASC

Another reason that I like name_scope is that because models such as these are frequently eused in dropdowns, etc, you can use named scope to return a very lightweight version of the class, while excluding attributes that are unnecessary for a simple dropdown. For example:

  1. class Region < ActiveRecord::Base
  2. belongs_to :country
  3. named_scope :ordered, :order => “name ASC”
  4. named_scope :by_country, lambda { |c| { :conditions => [“country_id = ?”, c.id] } }
  5. named_scope :containing, lambda { |s| { :conditions => [“name like ?”, “%#{s}%”] } }
  6. named_scope :simple, :select => “id, name”
  7. end

This allows me to only bring back the attributes that I need. And again, it could be chained with other named scopes

I think that this is a very powerful concept that allows developers to write more DRY and readable code.

Gửi phản hồi

Mời bạn điền thông tin vào ô dưới đây hoặc kích vào một biểu tượng để đăng nhập:

WordPress.com Logo

Bạn đang bình luận bằng tài khoản WordPress.com Log Out / Thay đổi )

Twitter picture

Bạn đang bình luận bằng tài khoản Twitter Log Out / Thay đổi )

Facebook photo

Bạn đang bình luận bằng tài khoản Facebook Log Out / Thay đổi )

Google+ photo

Bạn đang bình luận bằng tài khoản Google+ Log Out / Thay đổi )

Connecting to %s

%d bloggers like this: