0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

[Rails] ransackで複数ワードでの検索を行えるようにする

Last updated at Posted at 2025-04-04

はじめに

個人開発中のRailsアプリで、複数のワードによる検索機能を実装したので、その方法を共有します。
やることをより具体的に説明すると「ネコ カフェ」と検索をした時に、「ネコカフェ」のように「ネコ」と「カフェ」の両方のワードが含まれているモデルを取得する処理の実装になります。
なお、今回の記事は、Ransackが既に導入されていることを前提としています。

変更前と変更後のコード

以下が変更前と変更後のコードになります。
変更箇所はコントローラーのみでビューの変更は行っていません。
変更前のコードはransackのテンプレート的なものになるので説明は割愛して、次の章では変更後のコードがどのようなことをしているのかを解説していきたいと思います。

コントローラー(変更前)
  def index
  
    @q = Shop.ransack(params[:q])
    
    @shops = @q.result(distinct: true)
    
  end
コントローラー(変更後)
  def index

    key_words = params[:q][:name_cont].split(/[\p{blank}\s]+/)

    grouping_hash = key_words.reduce({}) do |hash, word|
        hash.merge(word => {name_cont: word})
    end
      
    @q = Shop.ransack({
      combinator: "and", 
      groupings: grouping_hash
      })
  
    @shops = @q.result(distinct: true)
  end 
ビュー
<div class="col-md-4">
    <%= form.text_field 'q[name_cont]', value: params.dig(:q, :name_cont), class: "form-control", placeholder: "ショップ名で検索" %>
</div>

複数ワード検索の実装方法

先ほどもお見せした以下の変更後のコードを詳しく解説していきます。

コントローラー(変更後)
  def index

    key_words = params[:q][:name_cont].split(/[\p{blank}\s]+/)

    grouping_hash = key_words.reduce({}) do |hash, word|
        hash.merge(word => {name_cont: word})
    end
      
    @q = Shop.ransack({
      combinator: "and", 
      groupings: grouping_hash
      })
  
    @shops = @q.result(distinct: true)
  end 

1.スペース区切りで送られてきた検索ワードを分割

以下のコードでは送られてきた検索ワード(params[:q][:name_cont])をsplitメソッドで配列に変換しています。
splitメソッドの引数 /[\p{blank}\s]+/ は、空白文字で検索ワードを分割するための正規表現です。
具体的に説明すると「ネコ カフェ」と検索された時のkey_wordsの中身は["ネコ", "カフェ"]という配列になります。

key_words = params[:q][:name_cont].split(/[\p{blank}\s]+/)

2.ransackで検索を行えるようにハッシュ形式に変換

以下のコードでは1で作成した配列(key_words)をransackで複数ワード検索を行うためにハッシュ形式へ変換を行います。

grouping_hash = key_words.reduce({}) do |hash, word|
    hash.merge(word => {name_cont: word})
end

具体的に先ほどのkey_wordsは以下のような形に変換されてgrouping_hashに代入されます。

grouping_hash = {
  "ネコ" => { name_cont: "ネコ" },
  "カフェ" => { name_cont: "カフェ" }
}

3.検索オブジェクトの作成

2で作成したgrouping_hashを用いてransackの検索オブジェクトの作成を行います。
「combinator: "and"」はand検索を行う設定でもし「combinator: "or"」の場合はor検索が行われます。
次に「groupings: grouping_hash」は検索条件をグループ分けすることで複数の条件で検索が行えるようにするための記述になります。

@q = Shop.ransack({
  combinator: "and", 
  groupings: grouping_hash
})

上記のように記述することで以下のようなSQL文となり、「ネコ」と「カフェ」の両方を含んだshopを検索するための検索オブジェクトが作成されます。

SELECT * FROM shops
WHERE name LIKE '%ネコ%'
  AND name LIKE '%カフェ%'

4.検索結果を取得する

最後に3で作成した検索オブジェクトを用いて条件に該当するshopの検索を行います。

@shops = @q.result(distinct: true)

まとめ

今回は、Ransackを使って複数ワードによるAND検索を行う方法について解説しました。
最後まで読んでいただきありがとうございます。

参考文献

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?