Rails 5-具有最新has_many关联的范围

时间:2018-09-23 23:32:34

标签: ruby-on-rails ruby ruby-on-rails-5

我正在为我的用户模型创建一个过滤表。我创建了一些作用域来过滤它们。我是:

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只会返回所有用户。

那么,如果未为其应用过滤器,该如何跳过范围?

1 个答案:

答案 0 :(得分:1)

类似的事情应该可以解决问题,它还有助于保护您的 send 方法。由于只能执行列入白名单的方法。下面的代码执行以下操作:

  1. 首先使用允许的键和允许的值创建白名单。
  2. 获取params[:statuses],如果不存在,则创建一个新的 Parameters 对象。
  3. 只允许允许的键。
  4. 删除所有没有列入白名单的键值实例。
  5. 将允许的参数转换为哈希。
  6. 减少生成的集合。以Vehicle.all开头并发送白名单方法(将它们链接在一起)。如果不存在键或值,则不会对其进行循环,因此无需调用:__self__:itself
  7. 执行其余的逻辑。

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

参考: