LoginSignup
67
56

More than 5 years have passed since last update.

ransackを使った複数ワードによるAND検索の実装

Last updated at Posted at 2016-06-07

ransackを使って複数語でのAND検索を実装しようと思ったら、意外と情報が少なかったのでメモ。

ransackを用いた検索機能の実装としては、以下のようなものが最低構成だと思う

class EventController
  def index
    keyword = params[:q] # params[:q] = 'hello'
    @event = Event.ransack(title_cont: keyword).result
  end
end

上記の例では、Eventモデルのtitleカラムに対して'hello'という文字列でLIKE検索を実行している。

これに対して、キーワードを複数用いてAND検索を行いたい場合は、ransackに以下のようにパラメータを渡す

def index
  keyword = params[:q].split(' ') # params[:q] = 'hello world'
  @event = Event.ransack({ combinator: 'and', groupings: { 'a' => {title_cont: keyword[0]}, 'b' => {title_cont: keyword[1]}} })
end

この例では、Eventモデルのtitleカラムに対して'hello'と'world'の二つの文字列でAND検索(LIKE)を実行している。ちなみに、groupings内の'a'や'b'の部分は、ユニークな値なら何でも構わない。

さらに、ソートの条件を指定する場合は以下のように行う

@event = Event.ransack({ combinator: 'and', groupings: { 'a' => {title_cont: keyword[0]}, 'b' => {title_cont: keyword[1]}}, s: 'title desc' })

これらを踏まえた、最低限のAND検索の実装が以下。

def index
  key_words = params[:q].split(/[\p{blank}\s]+/) # params[:q] = 'hello world ruby'
  grouping_hash = keywords.reduce({}){|hash, word| hash.merge(word => { title_cont: word })}
  Event.ransack({ combinator: 'and', groupings: grouping_hash, s: 'title desc' }).result
end

params[:q]には半角スペースあるいは全角スペースで区切られた形で、複数の検索ワードが入っている(今回は'hello world ruby')。2行目では検索ワードを分割し、配列に格納している。3行目では、ransackに渡すgroupingsパラメータの中身を組み立てている。この例では、以下のようなハッシュが形成される

{
  'hello' => {title_cont: 'hello'},
  'world' => {title_cont: 'world'},
  'ruby' => {title_cont: 'ruby'}
}

最終的に4行目ではransackメソッドにパラメータが渡され、"titleカラムにhello、world、rubyの文字列がいずれも含まれる"という条件を満たすモデルを絞り込むことができる。

67
56
2

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
67
56