这可能不是您问题的确切答案,但因为我自己在 Ransack 中搜索了正确的方法来进行 OR 搜索,但没有找到好的答案,但确实自己解决了问题,所以我我想我会分享解决方案。
在我正在处理的一个应用程序中,有一个搜索页面将模型Customer 的各个字段作为参数(链接到数据库表customers),然后列出与搜索结果匹配的这些客户的表.客户拥有三个不同的电话号码字段,并且之前的搜索页面为每种类型的号码提供了不同的搜索字段。我想将它们合并到一个字段中,以便在所有数字中方便地搜索。
数据库有这三个字段定义(在这些sn-ps中,我只更改了一些标识符名称):
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 .