【发布时间】:2012-08-02 23:15:10
【问题描述】:
我有一个模型的索引视图,我想通过模型属性的某种组合进行过滤。
例如,我有一个账单模型(不是鸭子上的那种,你必须支付的那种),我可能会根据收款人和/或状态进行过滤。
模型对每个单独的属性都有一个范围,例如
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
'除了它不起作用,因为Bill.all 是一个数组。另外,这并不好玩,因为Bill.all 执行查询,多亏了 AREL 的魔法,我只想运行一次。我应该只定义一个像all_bills 这样的范围吗(没有条件?)——我猜那将是一个ActiveRecord::Relation...
有没有更优雅地解决这个问题的模式?每当我有代码来做一件依赖于模型、视图和控制器的事情时,我都会觉得我可能做错了什么。或者好像比我更聪明、更努力的人已经解决了它:-)
额外问题:我希望这一切都能与我选择的分页器一起使用,这是最优秀的 Kaminari 宝石。
欢迎所有想法和想法。
【问题讨论】:
-
你试过has_scope吗?我刚刚在另一个问题上推荐了这个stackoverflow.com/a/11820424/167614
-
嗨@beerlington has_scope gem 看起来很有趣,它来自 Platformatec 团队的血统是无可挑剔的。我偏爱来自@mu-is-too-short 的另一个线程的答案,它解决了我的方法的一个基本问题——而不是从
@bills = Bill.all开始,我可以从@bills = Bill开始(它提供了基础AREL 范围链接),然后在最后使用@bills = @bills.all运行整个过程。两种解决方案都很棒。现在确保他们都与 Kaminari 一起工作以进行分页。谢谢。 -
has_scope 绝对适用于 will_paginate,所以如果它也不适用于 Kaminari,我会感到惊讶。
标签: ruby-on-rails-3 activerecord arel