学習記録

アウトプット用に作りました

ransackを使って検索機能を実装する

ransackとは

Railsで検索機能を実装する場合に使用するgemです。


使い方

gemfileにgem 'ransack'を導入して、bundle installします。
gemを新たに追加した時は、サーバーを再起動させる必要があります。


まずコントローラを作成していきます。

def index
  @q = Tweet.ransack(params[:q])
  @tweets = @q.result(distinct: true).includes(%i[user likes]).order(created_at: :desc).page(params[:page])

一番目のコードのransackは、paramsで受け取るときに、
この受け取った値が空だと、ransackの機能で投稿を全件取得することができます。
なので投稿の一覧画面で全件取得するために、わざわざ
@tweets = Tweet.all.includes(%i[user likes]).order(created_at: :desc).page(params[:page])
のように全件取得するためのコードをプラスで書く必要はありません。

二番目のコードの(distinct: true)が必要になるのは、
関連する子テーブルの情報を条件に絞り込んで、
親テーブルの検索結果を表示するときです。

例えば、絞り込み要件が「〇〇というコメントがついている掲示板を取得する」場合に、
distinct: trueをつけないと、一つの投稿に指定の文字が含まれているコメントが三つあると
三つ同じ投稿を取得してしまい、結果がおかしくなります。
なので、今回のようにdistinct: trueが必要でない場合でも、
書くくせをつけておけばいいです。


次はフォームを実装していきます。
ここで使うのがransackで使える`search_form_forメソッドです。

<%= search_form_for @q, url: url do |f| %>
      <%= f.search_field :title_or_body_cont %>
      <%= f.submit %>
<% end %>

このメソッドを使うとき、urlオプションを指定することで、
ルーティングして欲しいアクションにリクエストすることができます。
例えばいいね一覧の検索フォームの中から検索したいときに、
urlオプションでルーティングを指定しないと、
デフォルトでtweets#indexになってしまします。

またこのメソッドの中のurlオプションでrequest.pathを使うこともできます。
requestには、現在アクセスしているパスの情報が入っています。
しかしこのメソッドをパーシャルに分けて使おうとしたときに注意が必要です。
例えば投稿の詳細画面に検索機能をつけるときに、
送られるurlに投稿のidが含まれてしまいurlオプションの形式に合わなくなります。
なのでrequest.pathはパーシャルテンプレートでは使わないようにします。


:title_or_body_contでtitleカラムとbodyカラムの両方に対して
検索をかけることができるようになります。