这可能不是您问题的确切答案,但是因为我自己用谷歌搜索了在 Ransack 中进行 OR 搜索的正确方法,但没有找到好的答案,但我自己设法解决了问题,我想我d 分享解决方案。
在我正在处理的应用程序中,有一个搜索页面,它将模型的各个字段Customer
(链接到 DB 表customers
)作为参数,然后列出与搜索结果匹配的那些客户的表。客户拥有三个不同的电话号码字段,并且之前的搜索页面对每种类型的号码都有不同的搜索字段。我想将它们组合到一个字段中,以便在所有数字中方便地搜索。
数据库有这三个字段定义(在这些片段中,我只更改了一些标识符名称):
mysql> desc customers;
+--------------------------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------------------------+------------------+------+-----+---------+----------------+
...
| customer_phone_a | varchar(50) | YES | | NULL | |
| customer_phone_b | varchar(50) | YES | | NULL | |
| customer_phone_c | varchar(50) | YES | | NULL | |
+--------------------------+------------------+------+-----+---------+----------------+
以前,搜索页面(文件app/views/customers/index.html.erb
)包含以下内容:
<%= search_form_for @search do |f| %> <!-- this is a Ransack-provided form -->
<div class="field">
...
<%= f.label :customer_phone_a_spaces_match_anything, "Phone number A is or contains:" %>
<%= f.text_field :customer_phone_a_spaces_match_anything %>
<%= f.label :customer_phone_b_spaces_match_anything, "Phone number B is or contains:" %>
<%= f.text_field :customer_phone_b_spaces_match_anything %>
<%= f.label :customer_phone_c_spaces_match_anything, "Phone number C is or contains:" %>
<%= f.text_field :customer_phone_c_spaces_match_anything %>
...
</div>
<div class="actions">
<%= f.submit "Search", class: "btn btn-large btn-primary" %>
</div>
<% end %> <!-- search_form_for -->
(这与现在无关,但文件的内容config/initializers/ransack.rb
是:
Ransack.configure do |config|
config.add_predicate 'spaces_match_anything',
:arel_predicate => 'matches', # so we can use the SQL wildcard "%"
# Format the incoming value: add the SQL wildcard character "%" to the beginning and the end of
# the string, replace spaces by "%", and replace multiple occurrences of "%" by a single "%".
:formatter => proc {|v| ("%"+v.gsub(" ", "%")+"%").squeeze("%")}
end
这意味着除了 Ransack 的默认eq
,cont
等之外,我还可以spaces_match_anything
在搜索中使用我的自定义谓词。谓词做它所说的。)
无论如何,从您所做的同一个示例中获得灵感,我将以下 ransacker 添加到模型中app/models/customer.rb
:
ransacker :all_phones do |parent|
Arel::Nodes::InfixOperation.new('||',
Arel::Nodes::InfixOperation.new('||',
Arel::Nodes::InfixOperation.new('||', parent.table[:customer_phone_a]||"", ' '),
parent.table[:customer_phone_b]||"", ' '),
parent.table[:customer_phone_c]||"")
end
最后,我将搜索页面中的三个电话号码搜索字段替换为:
<%= f.label :customer_phone_a_or_customer_phone_b_or_customer_phone_c_cont, "Phone number is or contains:" %>
<%= f.text_field :customer_phone_a_or_customer_phone_b_or_customer_phone_c_cont %>
用户在此搜索字段中输入的数字现在将匹配客户的三个数字中的任何一个。(请注意在 ransacker 中对空数 , 的防范||""
。)
这经过测试可与 Ruby v1.9.3 和 Rails v3.2.8 一起使用。输入参数将不匹配一个数字的结尾和下一个数字的开头,即使在正确的位置输入空格也不匹配,即使在搜索字段代码中,我替换_cont
为_spaces_match_anything
。