使用 Ransack 搜索值数组
Search an array of values with Ransack
我是 Ransack 的新手,我已经 运行 研究了一个似乎没有被 Ransack 完全涵盖的案例。我基本上是在尝试搜索一个值,但搜索到的值包含在一个数组中。
代码:
<%= 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 %>
最后有一段 user_rep_code_list_cont
这是用户的默认数组属性,目前看起来像这样 ["al20", "b234"]
因此,当我在 Ransack 搜索栏中键入 al20 时,出现了此错误。
错误:
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.
控制器:
def index
@q = Submission.submissions_for(user: current_user).ransack(params[:q])
@submissions = @q.result.includes(:user, :accounts).ordered(current_user).page(params[:page]).per(25)
end
同样,我不是 Ransack 专家,但这似乎是现在应该涵盖的内容。我想搜索数组模型的属性。
使用数组和 Ransack 并不是那么简单,您必须手动完成大量工作,因为底层查询会很快将您带入高级领域。检查数组中的成员资格是 , checking every element of an array against a LIKE pattern is somewhat more complicated,因为您需要对 unnest
函数调用执行 LATERAL JOIN 以解包数组,以便您可以对其成员进行 LIKE:
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,用单独的 table 替换数组,这样您就可以使用 Ransacker 的关联逻辑并像对待第一个一样对待代码 class 数据库中的实体而不仅仅是字符串。某种完整的测试搜索(而不是 Ransack)可能是另一种选择。
您也许可以使用 PostgreSQL 的 array_to_string
函数来展平数组,但随后您将不得不处理定界符,并且您仍然会被 "do it all" 作用域所困(或者也许是一个自定义的劫掠者)。
对于这种情况,我最终使用了自定义 Ransacker
:
ransacker :rep_code_list do
Arel.sql("array_to_string(rep_code_list, ',')")
end
这会将数组转换为字符串,以便 Ransack 可以使用 cont
谓词进行搜索。不确定这是否是最好的方法,但它适用于我的情况。
我是 Ransack 的新手,我已经 运行 研究了一个似乎没有被 Ransack 完全涵盖的案例。我基本上是在尝试搜索一个值,但搜索到的值包含在一个数组中。
代码:
<%= 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 %>
最后有一段 user_rep_code_list_cont
这是用户的默认数组属性,目前看起来像这样 ["al20", "b234"]
因此,当我在 Ransack 搜索栏中键入 al20 时,出现了此错误。
错误:
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.
控制器:
def index
@q = Submission.submissions_for(user: current_user).ransack(params[:q])
@submissions = @q.result.includes(:user, :accounts).ordered(current_user).page(params[:page]).per(25)
end
同样,我不是 Ransack 专家,但这似乎是现在应该涵盖的内容。我想搜索数组模型的属性。
使用数组和 Ransack 并不是那么简单,您必须手动完成大量工作,因为底层查询会很快将您带入高级领域。检查数组中的成员资格是 unnest
函数调用执行 LATERAL JOIN 以解包数组,以便您可以对其成员进行 LIKE:
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,用单独的 table 替换数组,这样您就可以使用 Ransacker 的关联逻辑并像对待第一个一样对待代码 class 数据库中的实体而不仅仅是字符串。某种完整的测试搜索(而不是 Ransack)可能是另一种选择。
您也许可以使用 PostgreSQL 的 array_to_string
函数来展平数组,但随后您将不得不处理定界符,并且您仍然会被 "do it all" 作用域所困(或者也许是一个自定义的劫掠者)。
对于这种情况,我最终使用了自定义 Ransacker
:
ransacker :rep_code_list do
Arel.sql("array_to_string(rep_code_list, ',')")
end
这会将数组转换为字符串,以便 Ransack 可以使用 cont
谓词进行搜索。不确定这是否是最好的方法,但它适用于我的情况。