我正在为我的用户模型创建一个过滤表。我创建了一些范围来过滤它们。我是 :
class User < ApplicationRecord
has_many :invoices
scope :application_approved, -> { ... }
scope :application_denied, -> { ... }
scope :latest_invoice_paid, -> { ... }
scope :latest_invoice_not_paid, -> { ... }
def self.__self__
self
end
end
在控制器中:
def index
filters = params[:statuses] || {}
application_status = filters[:application_status].presence
payments_status = filters[:payments_status].presence
@vehicles = Vehicle.send(application_status || :__self__)
.send(payment_status || :__self__)
.paginate(:page => params[:page], :per_page => 10)
.order('created_at DESC')
end
所有筛选器都独立工作,但是当链接时,未应用的筛选器似乎会抵消早期的筛选器。
例如,如果我将过滤器设置为仅显示已付款的用户,则它可以工作。但是,如果我将过滤器设置为仅显示已批准/未批准的用户,则所有用户将始终返回。似乎在未应用过滤器时返回self
只是返回所有用户。
那么,如果未应用过滤器,如何跳过范围?
像这样的东西应该可以解决问题,它还有助于保护您的发送方法。因为只能执行列入白名单的方法。下面的代码执行以下操作:
- 首先使用允许的密钥和允许的值创建白名单。
- 获取
params[:statuses]
,如果不存在,则创建新的参数对象。 - 仅允许允许的密钥。
- 删除所有没有列入白名单值的键值实例。
- 将允许的参数转换为哈希。
- 减少生成的集合。从
Vehicle.all
开始,然后发送列入白名单的方法(将它们链接在一起(。如果键或值不存在,则不会循环,因此无需调用:__self__
或:itself
。 - 做你剩下的逻辑。
def index
whitelist = ActiveSupport::HashWithIndifferentAccess.new(
application_status: %w[application_approved application_denied],
payments_status: %w[latest_invoice_paid latest_invoice_not_paid],
)
filters = params[:statuses] || ActionController::Parameters.new
@vehicles =
filters
.permit(*whitelist.keys)
.select { |key, value| whitelist[key].include?(value) }
.to_h
.reduce(Vehicle.all) { |vehicles, (_key, value)| vehicles.send(value) }
.order(created_at: :desc)
.paginate(page: params[:page], per_page: 10)
end
引用:
- ActiveSupport::HashWithIndifferentAccess
- 动作控制器::P arameter(许可、选择和to_h都可以在这里找到(
- 可枚举#减少
- 板片运算符
*
.permit(*whitelist.keys)