与hansack进行OR

时间:2012-10-17 18:12:10

标签: ruby-on-rails ransack

基本问题,但我在project pagewiki找不到明确的内容。我有以下代码:

field = "secre"
Position.search( {:description_cont => field, :code_cont => field}).result(:distinct => true).to_sql
 => "SELECT DISTINCT `positions`.* FROM `positions`  WHERE ((`positions`.`description` LIKE '%secre%' AND `positions`.`code` LIKE 0))"

但我的查询应该是:

 => "SELECT DISTINCT `positions`.* FROM `positions`  WHERE ((`positions`.`description` LIKE '%secre%' OR `positions`.`code` LIKE 0))"

任何帮助将不胜感激。提前致谢

5 个答案:

答案 0 :(得分:4)

尝试以下方法:

Position.search( {:description_or_code_cont => field}).result(:distinct => true).to_sql

答案 1 :(得分:1)

这可能不是你问题的确切答案,但因为我在谷歌搜索正确的方式在Ransack自己进行OR搜索,并没有找到一个好的答案,但确实设法自己解决问题,我以为我会分享解决方案。

在我正在处理的应用程序中,有一个搜索页面,它将模型Customer的各个字段(链接到数据库表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的默认eqcont等,我还可以在搜索中使用自定义谓词spaces_match_anything。谓词就是这么说的。)

无论如何,从你所做的同一个例子中获取灵感,我将以下的搜索者添加到模型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 %>

用户在此搜索字段中输入的数字现在将匹配客户的三个数字中的任何一个。 (请注意在搜捕者中防止空号码||""。)

经过测试,可以使用Ruby v1.9.3和Rails v3.2.8。输入参数将不匹配一个数字的结尾和下一个数字的开头,即使在正确的位置输入空格也是如此,即使在搜索字段代码中,我也不会将_cont替换为{ {1}}。

答案 2 :(得分:1)

将此内容放在search_form_for标记下。这假设您正在使用f:

<%= f.combinator_select %>

它会生成一个带有两个选项的选择。全部或任何。任何人都会使用OR条款。 ALL将使用AND子句。

答案 3 :(得分:1)

目前,我们可以将ors查询与ransack一起使用非常简单:

Position.ransack(description: 'secret').result.or(Position.ransack(code: 0).result)

答案 4 :(得分:0)

在挖掘Ransack demo代码后,我按照以下方式进行了操作:

field = "secre"
q= {
  "m"=>"or", 
  "c"=>{
    "0"=>{
      "a"=>{
        "0"=>{
          "name"=>"description"
        }
      }, 
      "p"=>"cont", 
      "v"=>{
        "0"=>{
          "value"=>field
        }
      }
    }, 
    "1"=>{
      "a"=>{
        "0"=>{
          "name"=>"code"
        }
      }, 
      "p"=>"cont", 
      "v"=>{
        "0"=>{
          "value"=>field
        }
      }
    }
  }
}
Position.search(q).result(:distinct => true).to_sql
 => "SELECT DISTINCT `positions`.* FROM `positions`  WHERE ((`positions`.`description` LIKE '%secre%' OR `positions`.`code` LIKE 0))"

是的,这是严重的,并且肯定它不应该是最好的方式,但它暂时救了我。还有其他想法吗?