Ruby on Railsでransackを使った単一カラムに対する複数キーワードでの検索

勉強中のRailsで少し躓いたのでメモ。

www.imd-net.com
上記の記事を参考に検索機能を実装し、単一カラムに対して複数キーワードでの検索を行いたい。
参考記事内で“複数条件での部分一致”という言葉が出てくるが、それは「複数カラムに対して単一キーワードでの検索」で今回実装したい機能とは逆なので注意する。


まず、検索条件に合うname値をGitHubのransackから調べる。
ORの場合はcont_any (contains any)
ANDの場合はcont_all (contains all)

サンプルとして、descriptionに対してAND検索してみる。
参考記事内のapp/views/products/index.html.erbを以下のように書き換える。(15~18行目)

<div class="form-group">
  <%= f.label :description_cont_all %>
  <%= f.text_field :description_cont_all, class: "form-control", placeholder: "部分一致" %>
<div>

例えばこの状態でフォームに「hoge piyo」と入力して検索を実行すると、controllerにparams[:q]として以下のハッシュが渡る。
{"description_cont_all" => 'hoge piyo' }

上記のハッシュをransackに投げても、ハッシュの値である「スペースを含めた文字列」での検索が行われてしまうので、スペースで分割してハッシュの値を配列にする。
app/controllers/products_controller.rbを以下のようにする。

def index
  condition = Hash.new
  if params[:q].kind_of?(Hash)
    params[:q].each do |key, value|
      if key == 'title_cont_all' then
        condition[key] = value.split
      else
        condition[key] = value
      end
    end
  end
  @q = Item.ransack(condition)
  @items = @q.result
end


冗長な書き方になっているので、実際のところはハッシュをMarshalでディープコピーしてそれを書き換えた方がいいのかなって思います。