使用Ransack搜索值数组

时间:2018-03-19 19:24:22

标签: ruby-on-rails ruby ransack

我是Ransack的新手,而且我遇到了一个似乎并未被Ransack彻底覆盖的案例。我基本上试图搜索一个值,但搜索到的值被包装在一个数组中。

CODE:

data.table

最后有一块<%= f.search_field :category_or_account_number_or_status_or_account_number_or_account_name_or_accounts_name_or_accounts_number_or_user_name_or_user_rep_code_list_cont_any %> 是用户的默认数组属性,它现在看起来像这样[&#34; al20&#34;,&#34; b234&#34;]

因此,当我在Ransack搜索栏中键入al20时,我收到此错误。

ERROR:

user_rep_code_list_cont

控制器:

PG::UndefinedFunction: ERROR:  operator does not exist: character 
varying[] ~~* unknown
LINE 1: ..."name" ILIKE '%al20%') OR "users"."rep_code_list" ILIKE 
'%al...
                                                         ^
HINT:  No operator matches the given name and argument type(s). You 
might need to add explicit type casts.

同样,我不是Ransack专家,但这似乎是现在应该涵盖的事情。我想在作为Array的模型上搜索属性。任何帮助都会非常感谢!

2 个答案:

答案 0 :(得分:2)

我最终在这种情况下使用自定义Ransacker

ransacker :rep_code_list do
  Arel.sql("array_to_string(rep_code_list, ',')")
end

这会将数组转换为字符串,以便Ransack可以使用cont谓词进行搜索。不确定这是否是最好的方法,但它适用于我的情况。

答案 1 :(得分:1)

使用数组和Ransack并不是那么简单,您必须手动完成大量工作,因为基础查询会快速将您带入高级领域。检查数组中的成员资格是relatively easy,根据LIKE模式检查数组的每个元素是somewhat more complicated,因为您需要对unnest函数调用执行LATERAL JOIN来解包数组,以便你可以喜欢它的成员:

select users.*
from users, unnest(users.rep_code_list) c -- This is an implicit LATERAL JOIN
where c ilike '%some-pattern%'

并且你可能想在SELECT子句中抛出distinct on (users.id)来清理从查询的其他部分出现的任何重复项:

select distinct on (users.id) users.*
from users, unnest(users.rep_code_list) c -- This is an implicit LATERAL JOIN
where c ilike '%some-pattern%'
  and ...

要让Ransack使用此类查询,您需要添加范围(并告诉Ransack它可以使用范围)或者编写自定义ransacker。不幸的是,似乎没有办法让Ransack将通用attr1_or_attr2_or...参数名称解​​析逻辑与范围一起使用,因此您的范围必须全部完成:

class User < ApplicationRecord
  def self.ransackable_scopes(auth = nil)
    %i[things_like]
  end

  def self.things_like(s)
    select('distinct on (users.id) users.*')
      .joins(', unnest(users.rep_code_list) c')
      .where('c ilike :pat or users.category ilike :pat or ...', pat: "%#{s}%")
  end
end

然后以表格形式:

<%= f.search_field :things_like %>

你可能有更好的运气将LATERAL JOIN逻辑混合到一个自定义的ransacker中,或者更好的IMO,用一个单独的表替换数组,这样你就可以使用Ransacker的关联逻辑并将代码视为第一类实体数据库而不仅仅是字符串。某种完整的测试搜索(而不是Ransack)可能是另一种选择。

你可以用PostgreSQL的array_to_string功能做一些事情来压扁阵列,但是你必须处理分隔符,你仍然会遇到一个& #34;做到这一切&#34;范围(或者可能是自定义搜索者)。