我有一个模型的索引视图,我想通过模型属性的某种组合进行过滤。
例如,我有一个账单模型(不是鸭子上的那种,你必须支付的那种),我可能会根据收款人和/或状态进行过滤。
该模型对每个单独的属性都有一个范围,例如
scope :bill_status, lambda {|status| where("status = ?", status}
scope :bill_payee, lambda {|payee| where("payee_id = ?", payee.id}
该视图允许用户选择零个或多个选项——如果未选择一个选项,则表示“不按此过滤”。
在控制器中,我可以做一些像这样令人讨厌的事情:
def index
status = params[:bill][:status]
payee = params[:bill][:payee]
if status.present? and payee.present?
# chain scopes
@bills = Bill.bill_status(status).bill_payee(payee)
elsif status.present?
@bills = Bill.bill_status(status)
elsif payee.present?
@bills = Bill.bill_payee(payee)
else
@bills = Bill.all
end
# rest of controller action
end
但是,虽然这可行,但它既不美观也不易于扩展——添加第三个过滤器意味着我现在有更多的可能性。我追求美丽和纯洁。
假设我的范围都是可链接的,看来我应该能够做类似的事情
def index
@bills = Bill.all
@bills = @bills.bill_status(params[:bill][:status]) if params[:bill][:status].present?
@bills = @bills.bill_payee(params[:bill][:payee]) if params[:bill][:payee].present?
# rest of controller code
end
'cept 它不起作用,因为它Bill.all
是一个数组。另外,这并不好玩,因为Bill.all
执行查询,由于 AREL 的魔法,我只想运行一次。我应该只定义一个范围all_bills
(没有条件吗?)——ActiveRecord::Relation
我猜那是...
有没有更优雅地解决这个问题的模式?每当我有代码来做一件依赖于模型、视图和控制器的事情时,我都会觉得我可能做错了什么。或者好像比我更聪明、更努力的人已经解决了它:-)
额外的问题:我希望这一切都能与我选择的分页器一起使用,这是最优秀的 Kaminari 宝石。
欢迎所有想法和想法。