【Rails】ransackを使って検索機能の実装


検索機能の実装

今回はよくある検索バーの実装を行う。その際にransackと言うgemを使う。
ransackが提供する検索フォームにはシンプルモードアドバンスモードがある。
アドバンスモードは入れ子になったAND/OR検索など、かなり複雑なことが実現できるが、今回は基本的な利用が目的なのでシンプルモードで実装を行う。

手順
ransackのインストール
②コントローラーの編集
③viewの実装

ransackのインストール

Gemfileに以下のコードを記入後、bundle install

gem 'ransack'

②コントローラーの編集

掲示板に検索機能を追加する場合、以下のようにコントローラーの編集を行う。

boards_controller.rb
#このよくある1文を下記2行に変換
@boards = Board.all.includes(:user).order(created_at: :desc).page(params[:page])

↓↓

def index
  @q = Board.ransack(params[:q])
  @boards = @q.result(distinct: true).includes(:user).page(params[:page]).order("created_at desc")
end

params[:q]には検索パラメータが渡され、resultにより検索結果を得られる。

(distinct: true)は記載しなくても使えるが、例えば絞り込み要件が「xxxというコメントがついている掲示板を取得する」場合にdistinct: trueがないと結果がおかしくなる。
掲示板Aに対して「ruby1」というコメントと「ruby2」というコメントがあったとし、この(distinct: true)を入れなかったとき、rubyでコメントを検索した場合に、掲示板Aが2回取得されて検索結果が2件になってしまうからである。

③viewの実装


検索フォームはよく使われるので、パーシャルテンプレートとして作成。
search_form_forというransackが提供するフォームヘルパーを使ってフォームを作成。

#views/boards/_search.html.rb
<%= search_form_for @q, url: url do |f| %>
   <%= f.search_field :title_or_body_cont, class: 'form-control', placeholder: '検索ワード' %>
   <%= f.submit '検索', class: 'btn btn-primary' %>
<% end %>

#index.html.rb
<%= render 'search', q: @q, url: boards_path %>

url: urlと記入することで、どこからでも呼び出せる汎用性の高いパーシャルファイルになる。

例えば、すべての掲示板から検索したい場合は、url: boards_pathrenderに記載。ブックマークしている掲示板から検索したい場合は、url: bookmarks_boards_pathと記載…と言う風になる。

title_or_body_contはそのカラムのtitlebodyに検索した情報を含むレコード全てを取得する。

ransackのよく使う述語(predicate)

述語(predicate)とは、先程boardstitleとbodyを絞り込み検索する際に、title_or_body_contと表記したが、この_contの部分が述語(predicate)に該当する。複数検索を導入する際にはtitle_or_body_contにもある通り、_orを挟む。

*にはカラムを代入。

述語 意味(英語) 意味
*_eq equal 等しい
*_not_eq not equal 等しくない
*_lt less than より小さい
*_lteq less than or equal より小さい(等しいものも含む)
*_gt grater than より大きい
*_gteq grater than or equal より大きい(等しいものも含む)
*_cont contains value 部分一致(内容を含む)

選択による検索

下の図のように性別をボタンで選択し検索もできる。

example.rb
<%= search_form_for @q do |f| %>
  <%= f.label :sex %>
  <%= f.radio_button :sex_eq, '', {:checked => true} %>指定なし
  <%= f.radio_button :sex_eq, 1 %>男性
  <%= f.radio_button :sex_eq, 2 %>女性
  <%= f.submit "検索" %>
<% end %>

sex_eqによって選んだものと数字の1,2が一致しているかどうかを検索。

ソート機能

またransackには表示している情報を昇順降順で並び替える機能も備わっている。

index.html.rb
<tr>
  <th>Name</th>
  <th>Age</th>
  <th>Sex</th>
  <th>Address</th>
</tr>

↓以下のように変換すると、ソート機能が使える

<tr>
  <th><%= sort_link(@q, :name, "Name") %></th>
  <th><%= sort_link(@q, :age, "Age") %></th>
  <th><%= sort_link(@q, :sex, "Sex") %></th>
  <th><%= sort_link(@q, :address, "Address") %></th>
</tr>

参考記事

【Rails】ransackの使い方をざっくりまとめてみた
Rubyon Rails で検索機能を作ろう(ransack)
Ransackで簡単に検索フォームを作る73のレシピ