🗂

【Rails】検索機能の作成

2023/10/09に公開

まだ先ですがポートフォリオの構想を練っていて、この機能は絶対に使うだろうな~と思い復習のため作成します。

実装する機能

コントローラ

  • searchesコントローラ追加
  • searchアクション追加
  • 用途:検索を行う

ビュー

  • ログインしている場合に限り、ヘッダー下部に検索窓・検索ボタンを設置すること
  • 検索結果表示画面を作成し、検索結果を表示すること
  • 検索対象(ユーザーか投稿か)の選択かをプルダウンメニューで選択できること
  • 完全一致, 前方一致, 後方一致, 部分一致の検索手法をプルダウンメニューで選択できること

コントローラ作成

ターミナル
rails g controller searches

ルーティングの設定

config/routes.rb
Rails.application.routes.draw do
:
 get "/search", to: "searches#search"
:
end

ビュー作成

検索バーの作成

検索バーは部分テンプレートにして作成します。

views/searches/_form.html.erb
<% if user_signed_in? %>
  <%= form_with url: search_path, method: :get, local: true do |f| %>
    <%= f.text_field :content %>
    <%= f.select :model, options_for_select({"User" => "user", "Book" => "book"}) %>
    <%= f.select :method, options_for_select({"完全一致" => "perfect", "前方一致" => "forward", "後方一致" => "backward", "部分一致" => "partial"}) %>
    <%= f.submit "検索" %>
  <% end %>
<% end %>

解説↓

  • <% if user_signed_in? %>
    ユーザーがログインしているかチェックしている。ログインしている場合のみ検索フォームを表示している。
  • <%= form_with url: search_path, method: :get, local: true do |f| %>
    フォームを作成するメソッド。検索内容をルーティングに送信してくれる。
  • <%= f.text_field :content %>
    検索キーワードの入力用フィールドの表示と検索内容をcontentにしてアクションに送る。
  • <%= f.select :model, options_for_select({"User" => "user", "Book" => "book"}) %>
    モデルを選択するためのプルダウンメニュー、options_for_selectメソッドでUserモデルかBookモデルか選択できるようにしている。
  • <%= f.select :method, options_for_select({"完全一致" => "perfect", 以下省略}) %>
    上記と同じ
  • <%= f.submit "検索" %>
    検索ボタンを表示

部分テンプレートの呼び出し

views/layouts/applictaion.html.erb
<!DOCTYPE html>
<html>
:
<body>
    <%= render 'layouts/header' %>
      <main>
        <p id="notice"><%= notice %></p>
      + <div class="d-flex justify-content-center mb-2">
      +   <%= render "searches/form" %>
      + </div>
        <%= yield %>
      </main>
    <%= render 'layouts/footer' %>
  </body>
</html>

ヘッダー下に常に表示されるように記述。
Bootstrapのクラス指定をして水平方向中央寄せ、下部に2単位のマージン調整をしています。

Searchesコントローラへの記述

controllers/searches_controller.rb
class SearchesController < ApplicationController
  before_action :authenticate_user!
  
  def search
    @model = params[:model]
    @content = params[:content]
    @method = params[:method]
    
    if @model  == "user"
      @records = User.search_for(@content, @method)
    else
      @records = Book.search_for(@content, @method)
    end
  end
end

解説↓

  • 検索フォームからの情報
    検索モデル → params[:model]
    検索キーワード → params[:content]
    検索方法 → params[:method]
  • if @model == "user"
    選択されたものが"user"であるかの条件分岐。ユーザーを検索する。
  • @records = User.search_for(@content, @method)
    選択されたユーザーに対してsearch_forメソッドににて検索を行い、結果を@recordsに代入する。
  • else
    上記じゃない場合の条件分岐となるため、bookが検索される。
  • @records = Books.search_for(@content, @method)
    選択された検索対象(本)に対して、search_forメソッドにて検索を行い、結果を@recordsに代入する。

モデルへの記述

userモデル

models/user.rb
class User < ApplicationRecord
:
def self.search_for(content, method)
    if method == 'perfect'
      User.where(name: content)
    elsif method == 'forward'
      User.where('name LIKE ?', content + '%')
    elsif method == 'backward'
      User.where('name LIKE ?', '%' + content)
    else
      User.where('name LIKE ?', '%' + content + '%')
    end
  end   
end

解説↓

  • def self.search_for(content, method)
    contentは検索内容を表し、methodは検索方法を表しています。
  • 以下の4つの条件分岐を表している
    perfect完全一致検索
    forward前方一致検索
    backward後方一致検索
    partial部分一致検索
  • whereメソッドを使いデータベースから該当データを取得し、変数に代入する。
    whereメソッドにLIKE句を合わせ条件分岐を記述しています。LIKE句の記述例は下記のようになります。
    • 〜 WHERE 列名 LIKE '%検索値%'
    • 〜 WHERE 列名 LIKE '検索値_'
    • % → 0文字以上の任意の文字列
    • _ → 任意の1文字

bookモデル

models/book.rb
class Book < ApplicationRecord
:
 def self.search_for(content, method)
    if method == 'perfect'
      Book.where(title: content)
    elsif method == 'forward'
      Book.where('title LIKE ?', content + '%')
    elsif method == 'backward'
      Book.where('title LIKE ?', '%' + content)
    else
      Book.where('title LIKE ?', '%' + content + '%')
    end
  end
end

ちなみに僕はbookモデルに誤ってnameカラムを使用してしまいActiveRecord:Statementlnvalidエラーが出てしまいました笑
お気を付けください!

以上

参考

https://zenn.dev/yayu1303/articles/82ba1df75fa2ed
https://zenn.dev/ganmo3/articles/61143b30a08272
https://zenn.dev/goldsaya/articles/dbb47def37dcde

Discussion