這是一篇閱讀筆記,更詳細的內容請參考原文章:Active Record scopes vs class methods
class Post < ActiveRecord::Base
scope :published, where(status: 'published')
scope :draft, -> { where(status: 'draft') }
end
上面的例子中,第一種寫法在rails4中已經被deprecated,因為它的判斷式會在class第一次被載入的時候就會建立,在某些情況下會造成會錯誤的判斷,例如:
class Post < ActiveRecord::Base
scope :published_last_week, where('published_at >= ?', 1.week.ago)
end
上面的例子1.week.ago是以class載入的時間為計算點,而非每次呼叫scope的時候去計算一週前的時間。
scope其實就是class method,但它多了一些功能,第一個是它一定可以chainable,簡單來說就是可以與其它的scope串連使用。class method也可以做的到,但有些情況要自己去加,例如下面的例子:
class Post < ActiveRecord::Base
scope :by_status, -> status { where(status: status) if status.present? }
end
class Post < ActiveRecord::Base
def self.by_status(status)
if status.present?
where(status: status)
else
all
end
end
end
第二點是scope可以extensible,也就是可以定義某些scope必須要接在特定的scope之後才能用。class method也可以做到類似的事,但也要自己加,例子如下:
class Post < ActiveRecord::Base
scope :page, -> num { # some limit + offset logic here for pagination } do
def per(num)
# more logic here
end
def total_pages
# some more here
end
def first_page?
# and a bit more
end
def last_page?
# and so on
end
end
end
class Post < ActiveRecord::Base
def self.page(num)
scope = # some limit + offset logic here for pagination
scope.extend PaginationExtensions
scope
end
module PaginationExtensions
def per(num)
# more logic here
end
def total_pages
# some more here
end
def first_page?
# and a bit more
end
def last_page?
# and so on
end
end
end