📌

検索機能の追加

2023/08/01に公開

実装機能
・searchesコントローラ(searchアクション)
・ログイン中は常に検索ボックスを表示
・検索対象は User / Book の2択をプルダウンで選択
・検索方法は完全一致、部分一致、前方一致、後方一致の4つをプルダウンで選択
・検索結果一覧のビュー

前提
・deviseを使用
・userモデル / bookモデルを作成済み

step1 ルーティングの作成

config/routes.rb

get "search" => "searches#search"

step2 コントローラーの作成

$ rails g controller searches

searchesコントローラを作成する。

step3 ビューの作成(検索ボックス)

searches/_search_box.html.erb
<% if user_signed_in? %>
  <%= form_with url: search_path, method: :get, local: true do |f| %>
    <%= f.text_field :word %>
    <%= f.select :data, options_for_select([['User'], ['Book']]) %>
    <%= f.select :method, options_for_select([["完全一致", "perfect"], ["前方一致", "forward"], ["後方一致", "backward"], ["部分一致", "partial"]]) %>
    <%= f.submit "検索", class: "btn btn-secondary" %>
  <% end %>
<% end %>

・検索ボックスに入力する文字列 → word
 検索対象(User/Book) → data
 検索方法(完全一致/前方一致/後方一致/部分一致) → method
として、入力内容をアクションに送付します。

・options_for_selectは、選択肢を生成します。
 選択肢は引数の配列に入れます。
[['User'], ['Book']] この場合、選択肢のテキストと値は同じものになります。
[["完全一致", "perfect"], ["前方一致", "forward"], ...]
この場合、 配列の中の配列の1つ目が選択肢のテキスト、2つ目が値になります。

*form_with メソッド内に、local: true を記述することで、確実に同期通信を行うことができる。
https://qiita.com/kakudaisuke/items/e032c7705db00e8081dc

上記コードをレンダリングします。

layouts/application.html.erb
<%= render 'searches/search_box' %>

step4 アクションの作成

searches_controller.rb
  before_action :authenticate_user!
  
  def search
    @data = params[:data]
    @word = params[:word]
    @method = params[:method]
    if @data == "User"
      @users = User.look_for(@word, @method)
    else #@data == "Book"
      @books = Book.look_for(@word, @method)
    end
  end

・下部分のコードで、
 @data には、選択した検索対象(User/Book)
 @word には、検索ボックスに入力した値
 @method には、選択した検索方法(完全一致/前方一致/後方一致/部分一致)を代入します。

    @data = params[:data]
    @word = params[:word]
    @method = params[:method]

・検索対象が Userなら、 @usersに、
 検索対象が Bookなら、 @booksに、検索ボックスに入力した情報を代入します。

・look_for(word, method)は、これから定義します。

step5 look_for(条件分岐)の作成

models/user.rb
def self.look_for(word, method)
  if method == "perfect"
    @user = User.where("name LIKE ?", "#{word}")
   elsif method == "forward"
    @user = User.where("name LIKE ?", "#{word}%")
   elsif method == "backward"
    @user = User.where("name LIKE ?", "%#{word}")
   elsif method == "partial"
    @user = User.where("name LIKE ?", "%#{word}%")
  end
end 
models/book.rb
def self.look_for(word, method)
  if method == "perfect"
    @book = Book.where("title LIKE ?", "#{word}")
   elsif method == "forward"
    @book = Book.where("title LIKE ?", "#{word}%")
   elsif method == "backward"
    @book = Book.where("title LIKE ?", "%#{word}")
   elsif method == "partial"
    @book = Book.where("title LIKE ?", "%#{word}%")
  end
end 

以下の部分は

if method == "perfect"
    @book = Book.where("title LIKE ?", "#{word}")

method(検索方法)が、"perfect"なら、
Bookモデルのデータの中で、
titleが word(検索ボックスに入力した文字列)と同じもの
を全部 @bookに代入する
という意味になります。

("title LIKE ?", "#{word}")
("カラム名 LIKE ?", "検索したい文字列")

という感じです。

https://qiita.com/seri1234/items/765423c2c46ca4114da0

#{word}の前後についていたり、ついていなかったりする % は、
正規表現の書き方です。

https://qiita.com/shizuma/items/4279104026964f1efca6

step6 ビューの作成(検索結果一覧)

searchアクションで代入した、
@users または @books を用いて、一覧画面を作成します。

searches/search.html.erb

<h2>Results</h2>

<table class="table table-hover table-inverse">
  <% if @data == "User" %>
    <tbody>
      <% @users.each do |user| %>
        <tr>
          <td><%= image_tag user.get_profile_image, size: "50x50" %></td>
          <td><%= user.name %></td>
        </tr>
      <% end %>
    </tbody>
  <% else %>
    <tbody>
      <% @books.each do |book| %>
        <tr>
          <td><%= image_tag book.user.get_profile_image, size: "50x50" %></td>
          <td><%= book.title %></td>
          <td><%= book.body %></td>
        </tr>
      <% end %>
    </tbody>
  <% end %>
</table>

参照

https://qiita.com/hapiblog2020/items/6c2cef49df5616da9ae3

https://zenn.dev/goldsaya/articles/dbb47def37dcde#検索結果の一覧表示

Discussion