【问题标题】:Active Admin filter params passed to ransacker传递给 ransacker 的 Active Admin 过滤器参数
【发布时间】:2020-10-08 11:02:04
【问题描述】:

我正在尝试将几个 ID 传递给活动管理员的自定义 ransacker 过滤器

   filter :hasnt_purchased_product_items_in, as: :select, collection: -> { ProductItem.all }, multiple: true

勒索代码

ransacker :hasnt_purchased_product_items, formatter: proc { |product_id|
    users_who_purchased_ids = User.joins(:orders => :items).where("orders.status = 'success'").where("order_items.orderable_id IN (?)", product_id) # return only id-s of returned items.
    ids = User.where.not(id: users_who_purchased_ids).pluck(:id)
    ids.present? ? ids : nil # return ids OR nil!
} do |parent| # not sure why this is needed .. but it is :)
    parent.table[:id]
end 

这适用于单个查询,但不适用于多个查询,SQL 执行 2 个单独的搜索而不是一个

它正在运行以下 2 个语句

order.items.orderable_id IN ('90')

order.items.orderable_id IN ('91')

在 2 个单独的 SQL 语句中,而不是我想要的

order.items.orderable_id IN ('90','91')

来自活动管理页面的提交信息是

q[hasnt_purchased_product_items_in][]: 90
q[hasnt_purchased_product_items_in][]: 91

我认为我需要在 ransacker 阶段对传入参数做一些事情,但我不确定如何处理

【问题讨论】:

  • 您是否检查过params[:q][:hasnt_purchased_product_items_in] 是您所期望的数组?
  • 该 ransacker 行的性质 - proc { |product_id| } 意味着我会自动进入数组并检索值,这就是它运行 SQL 行两次的原因。 - 如果有办法将 id 作为字符串提交?
  • 是的,但它不应该介入。参数应该是 |product_ids| 并在 proc 中给我们一个数组对象,然后使用它。我会发布一些想法作为答案,如果它们不起作用,我会删除。
  • 使用 _in 会导致 noMethodError - nil:NilClass 的未定义方法 `klass'

标签: mysql arrays ruby-on-rails activeadmin ransack


【解决方案1】:

它不应该介入。参数应该是 |product_ids|并在 proc 中给我们一个数组对象,然后使用它。您的 ransacker 应返回活动记录关联或 arel 查询。

我会尝试这些:

  1. 在 ransacker 名称中使用“_in”,绕过数组逻辑。
ransacker :hasnt_purchased_product_items_in do |product_ids|
  users_who_purchased_ids = User.joins(orders: :items).where(orders: {status: 'success'}, order_items: {orderable_id: product_ids}) # return only id-s of returned items.
  User.where.not(id: users_who_purchased_ids)
end
  1. 相同的 ransacker 名称,但使用块而不是格式化程序。
ransacker :hasnt_purchased_product_items do |product_ids|
  users_who_purchased_ids = User.joins(orders: :items).where(orders: {status: 'success'}, order_items: {orderable_id: product_ids}) # return only id-s of returned items.
  User.where.not(id: users_who_purchased_ids)
end 

我不得不猜测要返回的对象,因为不清楚这个 ransacker 是在哪个模型上。如果你能告诉我目标(例如过滤用户的产品推荐以排除他们的购买),那么我可以更新答案。

  1. 创建一个作用域并使其可用于洗劫。

用户.rb

  scope :hasnt_purchased_product_items_in, ->(product_ids){
   users_who_purchased_ids = joins(orders: :items).where(orders: {status: 'success'}, order_items: {orderable_id: product_ids}) # return only id-s of returned items.
   where.not(id: users_who_purchased_ids)
  }

  def self.ransackable_scopes(auth_object = nil)
    %i(hasnt_purchased_product_items_in)
  end

然后这个工作:

User.ransack({hasnt_purchased_product_items_in: [[1,2,3]]}).result

注意,ransack want 是一个 args 数组。我们想要一个 arg,它是一个数组。

【讨论】:

  • 我得到一个 noMethodError 未定义的方法 'klass' for nil:Nilclass - 与使用 _in 选项的 ransacker 相关
  • 我似乎无法使用块而不是格式化程序,因为我需要 "splat_params: true do |parent| parent.table[:id] end" 部分 - 这将返回活动管理员
  • 目标是回馈没有购买特定商品的用户
  • 我添加了第三个使用范围的选项,并在本地进行了测试。剩下的唯一事情就是确保您传递的参数是数组中的一个 id 数组。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-04-17
  • 2021-12-02
  • 2012-07-29
  • 2013-08-17
  • 2018-04-14
相关资源
最近更新 更多