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.   
  5. class Country < ActiveRecord::Base   
  6.   has_many :regions  
  7. end  
class Region < ActiveRecord::Base
  belongs_to :country
end

class Country < ActiveRecord::Base
  has_many :regions
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  
class Region < ActiveRecord::Base
  #other code
  def self.ordered
    find(:all, :order => "name ASC")
  end
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  
class Region < ActiveRecord::Base
  named_scope :ordered, :order => "name ASC"
  #other code
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.   
  8. class Runner   
  9.  c = Country.find_by_name("Canada")   
  10.  regions = Region.by_country(c).containing("A").ordered   
  11.  puts "Provinces in Canada containing the letter A in ascending order: #{regions.inspect}"  
  12. end  
class Region < ActiveRecord::Base
  belongs_to :country
  named_scope :ordered, :order => "name ASC"
  named_scope :by_country, lambda { |c| { :conditions => ["country_id = ?", c.id] } }
  named_scope :containing, lambda { |s| { :conditions => ["name like ?", "%#{s}%"] } }
end

class Runner
 c = Country.find_by_name("Canada")
 regions = Region.by_country(c).containing("A").ordered
 puts "Provinces in Canada containing the letter A in ascending order: #{regions.inspect}"
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  
class Region < ActiveRecord::Base
  belongs_to :country
  named_scope :ordered, :order => "name ASC"
  named_scope :by_country, lambda { |c| { :conditions => ["country_id = ?", c.id] } }
  named_scope :containing, lambda { |s| { :conditions => ["name like ?", "%#{s}%"] } }
  named_scope :simple, :select => "id, name"
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.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值