本文介绍name scope的使用。是文档和其他人的文档的汇编。
数据库定义
create table orders (
id int not null auto_increment,
name varchar(100) not null,
email varchar(255) not null,
address text not null,
pay_type char(10) not null,
shipped_at datetime null,
primary key (id)
);
数据库抽象类
class Order < ActiveRecord::Base
end
简单示例
pp Order.find([22,23,24])
# 返回一个列表 列表每个元素为 Order类型(也就是继承的ActiveRecord::Base类型)
pp Order.scoped
# 返回一个 ActiveRecord::Relation类型,继承于ActiveRecord::Base类型
pp Order.find(:first, :conditions => { :name => "ottocho" })
k = Order.scoped(:conditions => { :name => "ottocho" })
pp k.find(:first)
什么是scope
我理解为接受了约束的数据抽象类对象 它代表的是在此约束下的此数据对象
类型
scope 返回的是ActiveRecord::Relation类型,继承于ActiveRecord::Base类型
find 返回的是一个列表,其中每个元素为定义的数据抽象类型(也是继承于ActiveRecord::Base类型)
他们两个返回的类型不同,但是都可以用each迭代
一个scope就可以利用迭代器了 如果还需要加其他约束条件 有两种做法
otto_order = Order.scoped(:conditions => { :name => "ottocho" })
pp otto_order.find(:first, :conditions => { :address => "guangzhou" })
pp otto_order.scoped(:conditions => { :address => "guangzhou" }).first
具体介绍:
named_scope功能:
在类定义中利用named_scope方法定义的scope,可以很便捷提供检索查询。
数据库抽象类
class Order < ActiveRecord::Base
named_scope :cash_pay, :conditions => { :pay_type => "cash" }
named_scope :card_pay, :conditions => { :pay_type => "card" }
named_scope :recent, lambda { { :conditions => ['created_at > ?', 1.week.ago] } }
end
示例
# 有人写的是"same as" 其实不同
# find返回的是列表(:all)或者单个对象(:first)
Order.cash_pay # Order.find(:all, :conditions => { :pay_type => "cash" })
Order.card_pay # Order.find(:all, :conditions => { :pay_type => "card" })
Order.recent # Order.find(:all, :conditions => ['created_at > ?', 1.week.ago])
# scope可以调用scope(scope返回的relations类型继承于ActiveRecord::Base,显然拥有此方法)
Order.card_pay.recent
# 有人写的是"same as" 其实不同
Order.with_scope(:conditions => { :pay_type => "card" }) do
Order.find(:all, :conditions => ['created_at > ?', 1.week.ago])
end
# 可以给命名的scope传递参数,使得在运行时指定条件
class Order < ActiveRecord::Base
named_scope :shipped, lambda { |time_ago| { :conditions => ['shipped_at > ?', time_ago] }
end
Order.shipped 7.days.ago
# 类似于:
# Order.find(:all, :conditions => ['shipped_at > ?', 7.days.ago])
# 可以为定义的scope定义方法
class Order < ActiveRecord::Base
named_scope :shipped, :conditions => ['created_at > ?', 1.week.ago] do
def cash_paid
each { |i| i.update_attribute(:pay_type, "cash") }
end
end
end
# 把装好的order设置为cash支付的
Order.shipped.cash_paid
# scoped也是个类方法 匿名定义
card_pay = Order.scoped(:conditions => {:pay_type => "card"})
recent = Order.scoped(:conditions => ['created_at > ?', 7.days.ago])
recent_card_pay = recent.card_pay
以下还有两个很好的范例:
平常我们在使用named_scope时,对于一些sql语句无法表达的集合筛选,总是需要进行select处理,代码读起来就不那么优雅。
named_scope + block 则解决了这个问题。
class User < ActiveRecord::Base
has_many :stories
named_scope :inactive, :conditions => {:active => false} do
def latest(number = 1, role = nil)
collection = role.blank? ? self : self.find_all_by_role(role)
collection[0, number]
end
end
end
# Re-activate all inactive users
User.inactive.latest(5,'admin')
rails中不仅named_scope可以这样写,has_many等关联方法 也可以 带block.例如:
class User < ActiveRecord::Base
has_many :stories do
def latest_public
self.select{|story| story.public? }.first
end
end
end
这两个例子中block内的self 都是代表当前集合,所以self其实是对集合做操作。
参考
http://ar.rubyonrails.org/
http://ar.rubyonrails.org/classes/ActiveRecord/Base.html
http://ar.rubyonrails.org/classes/ActiveRecord/NamedScope.html
http://www.cnblogs.com/orez88/articles/1580930.html
https://github.com/wvanbergen/scoped_search
https://github.com/wvanbergen/scoped_search/wiki/search-definition