掲示板の検索機能を実装(ransack)

<実現したいこと>

検索フォームの作成をする

♡検索フォームに入力された文言が掲示板のタイトルか本文に含まれている掲示板のみ表紙させる

♡ブックマーク一覧のページで検索した場合、「ブックマークした掲示板の中から」検索条件に合致したものを表示させる

<手順>

♡ransackの導入

♡コントローラーの編集

♡検索フォームの表記を使い回せるようパーシャルを作成

♡検索フォームを表記したいところにrenderで埋め込んでいく

 

①ransackの導入

Gemfileに

gem 'ransack'

を書き込み、bundle installする。

 

②コントローラの編集

今回はboard一覧から検索する処理、bookmark一覧から検索する処理を追加するため、

app/cotrollers/boards_controllersのindexとbookmarksアクションに編集を加える。

indexアクション部分

@q = Board.ransack(params[:q])
    @boards = @q.result(distinct: true).includes(%i[user bookmarks])
              .order(created_at: :desc).page(params[:page])

bookmarksアクションの部分

@q = current_user.bookmark_boards.ransack(params[:q])
    @bookmark_boards = @q.result(distinct: true).includes(:user)
                   .order(created_at: :desc).page(params[:page])

☆distinct: trueに必要性

コメントで検索をしていく場合、1つの掲示板(Aとする)に2つの「Ruby」(BとCとする)という文言が含まれたコメントがついているとする。コメント検索で「Ruby」と指定して、検索した場合、BとCどちらも検索に引っかかる。結果として”Bで検索したA”と”Cで検索したA”どちらもヒットしてしまい、検索結果に掲示板Aが2つ表示されることになってしまう。

そこでdistinct: trueがしてあることでAという掲示板は重複することなく表示される。

※今回の場合は必須ではないが、癖づけておくと良いということだった。

params[:q]に検索フォームで入力された文言が入ってきて、@qに格納される。

 

③検索フォームの表記を使い回せるようパーシャルを作成

app/views/boards/_search_form.html.erb

<%= 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: t('defaults.search_word') %>
    <div class="input-group-append">
     <%= f.submit class: 'btn btn-primary' %>
    </div>
  </div>
<% end %>

search_form_forはransackで用意されているヘルパー。

placeholderで検索フォームにデフォルトで表示されている文言を表示している。

title_or_body_cont掲示板のtitle(タイトル)とbody(本文)を最後の_contで検索できるようにしている。cont = contain 部分一致の検索が可能になるLIKE演算子。含まれているものを検索する。

f.submitのあとにすぐclassの指定をしているが、何もボタン表記の文言を指定しなければ自動で「検索」という表記になるため。

url: urlでurlオプションを設定し、リクエストするurlを指定している。④でrenderする際に、呼び出し側で指定したパスをローカル変数に渡す。どこからでも呼び出せる汎用性の高いパーシャルファイルにすることができるため、このような表記になっている。

 

④検索フォームを表記したいところにrenderで埋め込んでいく

掲示板一覧(app/views/boards/index.html.erb)

<%= render 'search_form', url: boards_path, q: @q %>

ブックマーク一覧(app/views/boards/bookmarks.html.erb)

<%= render 'search_form', url: bookmarks_boards_path,q: @q %> 

☆同じboards内にパーシャルを作成しているため、'boards/search_form'のboards部分を省略。

☆パーシャル内でインスタンス変数を用いてしまうと汎用性が低下してしまうため、ローカル変数を用いる。そこでq: @qはパーシャル内のローカル変数qに値を渡す。

☆url部分でリクエストするurlを渡している。