scope翻為中文是範圍
也可以理解為過濾器
在專案裡時常會為了實現一些商業邏輯,寫下一些很長的ActiveRecord
如果散落在專案內日後會不好管理
所以一般的做法是會整理到model內作為scope
比方說
class Dog < ApplicationRecord
scope :good, -> {where(status: :good)}
end
這樣做至少有兩個好處
第一是上面提到的管理方便,如果條件變更時
只需要更改一處即可
第二個好處是增加程式的可讀性
透過scope表達程式本身的意圖
例如
Dog.has_free_time.good.male
直接閱讀,大概就可以猜到
我想要找出所有公的、有空的好狗狗
scope也可以傳遞變數
寫法如下:
scope :where_status, -> (status) {where(status: status)}
# Dog.where_status("good")
假如說條件相當複雜,或是已經有現成的方法想放到條件當中
當然也是可以的,其實scope本身也就是model的class
所以上面的good scope效果其實與下面這種寫法相同
def self.good
where(status: :good)
end
另外一種做法,是透過select來傳遞條件
比方說
scope :can_signup, -> { select {|i| i.is_not_full? }}
def is_not_full?
#code here
end
如此就能將複雜的條件判斷,縮寫成為一個scope
是不是很方便呢?
假如這個條件相當重要
幾乎每一次執行都需要,那可以考慮設為default
例如default_scope order('rank ASC')
這樣就不論在專案的何處,都會預設執行(包含console)
要跳脫default方法如下Dog.unscoped.where(...)
加上unscoped,後面就可以繼續串接想要的判斷了
是不是很方便呢?