gem ransackを使用し検索機能の実装
実装内容
gem 'ransack'を使用し、掲示板一覧画面とブックマーク一覧画面に以下のようなフォームを設置する。
- 入力された文言が「掲示板のtitle,body」に含まれている掲示板のみを表示させる。
ブックマーク一覧のページで検索した場合は「ブックマークした掲示板の中から」検索条件に合致したものを表示させる。
掲示板一覧画面での検索はboards#indexアクション、
- ブックマーク一覧画面での検索はboards#bookmarksアクションで行う。
導入
gem 'ransack'
bundle install
controller
掲示板一覧(index)アクションとブックマーク一覧(bookmarks)アクションを修正
~ def index if logged_in? @q = Board.ransack(params[:q]) @boards = @q.result(distinct: true).includes(:user).order(created_at: :desc).page(params[:page]) else redirect_to login_path, danger: 'ログインしてください' end end def bookmarks @q = current_user.bookmark_boards.ransack(params[:q]) @bookmark_boards = @q.result(distinct: true).includes(:user).order(created_at: :desc).page(params[:page]) end ~
params[:q]
で検索フォームに入力した文字を取得(viewから送られてきたパラメータ)デフォルトで:q
となっている。→インスタンス変数@q
を定義。
ransack
メソッド、送られてきたパラメータをもとにテーブルからデータを検索。
result
メソッドでransackメソッドで取得したデータをActiveRecord_Relationのオブジェクトに変換し、検索結果を渡す。
(distinct: true)
で重複を防ぐ
includes
メソッドでN+1問題の回避。
order
メソッドで並び替え。
page
メソッドでページネーションの実装。
view
検索フォームのパーシャルを作成
<%= search_form_for q, url: url do |f| %> <div class='input-group mb-3'> <%= f.search_field :title_or_body_cont, class: 'form-control', placeholder: '検索ワード' %> <div class="input-group-append"> <%= f.submit '検索', class: 'btn btn-primary' %> </div> </div> <% end %>
search_form_for
メソッドはransackで用意されているメソッド
form_withやform_forと同じ
検索オブジェクトq
を指定。
url
オプションでリクエストするurlを渡す。→renderでパーシャルを読み込む時に指定。
f.search_field
で入力フォームを作成すると検索フォームとして作成される。
今までは文字の場合→f.text_field
で記述していた。
f.search_field
を指定することで、inputタグにtype="search"が記述され、フォームの右に「x」ボタンが表示されるようになる。
:title_or_body_cont
で検索対象のカラムを指定。今回は2つあるのでorで区切る。
パーシャルを読み込む
掲示板一覧画面とブックマーク一覧画面にパーシャルをレンダーさせる。
ローカル変数q
に値を渡す。
pathは各アクションのやつを指定。
〜 <!-- 検索フォーム --> <form> <%= render 'boards/search_form', url: boards_path, q: @q %> </form> 〜
<!-- 検索フォーム --> 〜 <form> <%= render 'boards/search_form', url: bookmarks_boards_path, q: @q %> </form> 〜