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カラムの両方に対して
検索をかけることができるようになります。