我正在为我的用户模型创建一个过滤表。我创建了一些作用域来过滤它们。我是:
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
只会返回所有用户。
那么,如果未为其应用过滤器,该如何跳过范围?
答案 0 :(得分:1)
类似的事情应该可以解决问题,它还有助于保护您的 send 方法。由于只能执行列入白名单的方法。下面的代码执行以下操作:
params[:statuses]
,如果不存在,则创建一个新的 Parameters 对象。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
参考:
.permit(*whitelist.keys)
中的splat operator *