微信号:ruby_and_rails

介绍:[Ruby程序员]旨在分享最新的Ruby & Rails,移动开发以及其他相关技术的分享,内容通俗易懂,有来自北京,上海,广州的技术达人不定期的分享.

Rails 4: Scope用法合集

2015-12-01 16:55 Michael
1 Scopes

Scopes 允许我们定义可重用的链式查询方法,声明一个scope,使用类方法scope, 后面跟查询语句,可以使用where, order, limit等Arel方法,当调用这个scope方式才会触发块内的查询。

1 class Timesheet < ActiveRecord::Base

2 scope :submitted, -> { where(submitted: true) }

3 scope :underutilized, -> { where('total_hours < 40') }

1 class User < ActiveRecord::Base

2 scope :delinquent,

-> { where('timesheets_updated_at < ?', 1.week.ago) }

像类方法一样调用这个scope.

>> User.delinquent

=> [#<User id: 2, timesheets_updated_at: "2013-04-20 20:02:13"...>]

等价于类方法

1 def self.delinquent

2 where('timesheets_updated_at < ?', 1.week.ago)

3 end

2 Scope Parameters

scope同时接受参数

1 class BillableWeek < ActiveRecord::Base

2 scope :newer_than, ->(date) { where('start_date > ?', date) }

BillableWeek.newer_than(Date.today)
3 Chaining Scopes

链式查询scope,可以使用scope做复杂查询,使代码更简洁,多个scope可一起使用

1 class Timesheet < ActiveRecord::Base

2 scope :submitted, -> { where(submitted: true) }

3 scope :underutilized, -> { submitted.where('total_hours < 40') }

>> Timesheet.underutilized.submitted.to_a

=> [#<Timesheet id: 3, submitted: true, total_hours: 37 ...

4 Scopes and has_many

scope同样在has_many关联关系中可用

>> u = User.find(2)

=> #<User id: 2, username: "obie"...>

>> u.timesheets.size

=> 3

>> u.timesheets.underutilized.size

=> 1

5 Scopes and Joins

也可以使用Arel的join方式创建一个跨类的scope方法。使用Arel的to_sql方法进行debug

1 scope :tardy, -> {

2 joins(:timesheets).

3 where("timesheets.submitted_at <= ?", 7.days.ago).

4 group("users.id")

5 }

>> User.tardy.to_sql

=> "SELECT "users".* FROM "users"

INNER JOIN "timesheets" ON "timesheets"."user_id" = "users"."id"

WHERE (timesheets.submitted_at <= '2015-11-30 18:16:15.203293')

GROUP BY users.id"

6 Scope Combinations

上个例子其实违背的面向对象的设计原则,不应该把用于确定是否提交时间表的逻辑放到该scope中,幸运的是

我们可以使用合并来解决这个问题,把两个业务分开。

scope :late,

-> { where("timesheet.submitted_at <= ?", 7.days.ago) }

scope :tardy,

-> { joins(:timesheets).group("users.id")

.merge(Timesheet.late)

}

7 Default Scopes

default_scope为默认的查询条件,甚至在创建对象的时候,在特定场合使用起来非常方便,但是如果不注意也会让人感觉很困惑

class Timesheet < ActiveRecord::Base

default_scope { where(status: "open") }

end

>> Timesheet.pluck(:status)

=> ["open", "open", "open"]

>> Timesheet.new

=> #<Timesheet id: nil, status: "open">

>> Timesheet.create

=> #<Timesheet id: 1, status: "open">

上面的例子中可以看到,创建和查询的时候,默认都会带上default_scope,那如果我想创建一个status为new

的对象怎么办呢? 可以使用下面方法覆盖

>> Timesheet.where(status: "new").new

=> #<Timesheet id: nil, status: "new">

>> Timesheet.where(status: "new").create

=> #<Timesheet id: 1, status: "new">

8 scoping

另一个时髦的方法scoping,可以在查询的时候内嵌block

>> Timesheet.order("submitted_at DESC").scoping do

>> Timesheet.first

>> end

=> #<Timesheet id: 1, status: "open">

9 unscoped

default_scope非常cool,但是有的时候我们并不需要它的这个特性,所以ActiveRecord提供了unscoped方法。

>> Timesheet.unscoped.order("submitted_at DESC").to_a

=> [#<Timesheet id: 2, status: "submitted">]


>> Timesheet.unscoped.new

=> #<Timesheet id: nil, status: nil>

Arel在Rails起到非常重要的作用,相信你应该对socpe有了新的认识。



 
ruby程序员 更多文章 rails 中使用roo读取excel数据 ruby中的鸭子类型(duck type) Rails中如何使用jsonp实现跨域访问 一道笔试题 ruby设计模式-单例模式
猜您喜欢 C++技术网第一届程序员交流大会圆满完成 第四十八讲 排序算法(3) 慕课网@你,一大波IT好书推荐! Python中的变量绑定[2] 抓包,只为让DBA过的更开心