##はじめに
閲覧ありがとうございます!
今回は「検索機能」の実装についてまとめていきます。
__ransack__という__Gemfile__を使うと
簡単に実装できるみたいですが、まだ学習しておりません...。
そのため、今回はransackを使わずに、
「検索機能」を実装していこうと思います!
ポイント
・複数のモデルを検索できるようにします。(今回はUserとBook)
・検索方法は完全一致、部分一致、前方一致、後方一致の4つ作ります。
・検索後は、検索結果一覧ページを表示します。
##目次
・開発環境
・前提条件
・ルーティング定義
・検索フォーム作成
・Searchesコントローラー作成
・モデル内に検索方法の分岐定義
・検索結果の一覧表示
##開発環境
・ruby: 2.6.3
・rails: 5.2.4.5
・OS: macOS Catalina ver10.15.7
・Cloud9
##前提条件
■下記モデル実装済み
・Userモデル
・Bookモデル
■device導入
■Bootstrap導入
##ルーティング定義
まずはルーティングから定義していきましょう。
get "search" => "searches#search"
検索ボタンが押された時、Searchesコントローラーのsearchアクションが実行されるように定義しました。
パス名は__「search_path」__です。
余談ですが、パス名は下記2種類の方法で確認することができます。
1:ターミナルにてrails routes
を実行
2:サーバーを起動し、URL末尾に/rails/info/routes
を追記
##検索フォーム作成
次に、検索フォームを設置します。
今回はヘッダー内に検索フォームを表示したかった為、部分テンプレートとして作成しています。
<% if user_signed_in? %>
<div class="search_form">
<%= form_with url: search_path, local: true, method: :get do |f| %>
<%= f.text_field :word %>
<%= f.select :range, options_for_select([['User'], ['Book']]) %>
<%= f.select :search, options_for_select([["完全一致","perfect_match"], ["前方一致","forward_match"], ["後方一致","backward_match"], ["部分一致","partial_match"]]) %>
<%= f.submit "検索", class: "btn btn-primary" %>
<% end %>
</div>
<% end %>
■解説
①url: search_path
検索内容を、先ほど作成したルーティングに送信します。
②<%= f.text_field :word %>
検索内容を、word
としてアクションに送っています。
③<%= f.select :range, options_for_select([['User'], ['Book']]) %>
今回は複数のモデルを検索できるように実装する為、
__Userモデル__と__Bookモデル__を選択できるようにしています。
選択したモデルをrange
としてアクションに送っています。
④ <%= f.select :search, options_for_select([["完全一致","perfect_match"]以下略]) %>
検索手法を定義しています。
今回のようにカンマ区切りで複数定義することができます。
選択した検索手法をsearch
としてアクションに送っています。
##Searchesコントローラーにアクション定義
まず、コントローラーを作成します。
rails g controller searches
次に、searchアクションを定義します。
class SearchesController < ApplicationController
before_action :authenticate_user!
def search
@range = params[:range]
if @range == "User"
@users = User.looks(params[:search], params[:word])
else
@books = Book.looks(params[:search], params[:word])
end
end
end
■解説
①下記コードにて検索フォームからの情報を受け取っています。
検索モデル→params[:range]
検索方法→params[:search]
検索ワード→params[:word]
②if文を使い、検索モデルUser
orBook
で条件分岐させます。
③looksメソッドを使い、検索内容を取得し、変数に代入します。
検索方法params[:search]
と、検索ワードparams[:word]
を参照してデータを検索し、
1:インスタンス変数@users
にUserモデル内での検索結果を代入します。
2:インスタンス変数@books
にBookモデル内での検索結果を代入します。
これでsearchアクションは完成です。
##モデル内に検索方法の分岐定義
しかし、このままでは検索方法による切替が行われません。
そこで、各モデルに条件分岐を追記します。
# 検索方法分岐
def self.looks(search, word)
if search == "perfect_match"
@user = User.where("name LIKE?", "#{word}")
elsif search == "forward_match"
@user = User.where("name LIKE?","#{word}%")
elsif search == "backward_match"
@user = User.where("name LIKE?","%#{word}")
elsif search == "partial_match"
@user = User.where("name LIKE?","%#{word}%")
else
@user = User.all
end
end
name
は検索対象であるusersテーブル内のカラム名です。
適宜、適したカラム名を指定しましょう。
# 検索方法分岐
def self.looks(search, word)
if search == "perfect_match"
@book = Book.where("title LIKE?","#{word}")
elsif search == "forward_match"
@book = Book.where("title LIKE?","#{word}%")
elsif search == "backward_match"
@book = Book.where("title LIKE?","%#{word}")
elsif search == "partial_match"
@book = Book.where("title LIKE?","%#{word}%")
else
@book = Book.all
end
end
title
は検索対象であるbooksテーブル内のカラム名です。
各々、適したカラム名を指定しましょう。
■解説
各検索方法を下記のように指定しました。
検索フォーム作成時に記載した内容を見返してみてください。
・完全一致→perfect_match
・前方一致→forward_match
・後方一致→backword_match
・部分一致→partial_match
送られてきたsearch
によって条件分岐させましょう。
そして、whereメソッドを使いデータベースから該当データを取得し、変数に代入します。
完全一致以外の検索方法は、
#{word}
の前後(もしくは両方に)、__%__を追記することで定義することができます。
これにより、検索方法毎に適した検索が行われるようになりました。
##検索結果の一覧表示
ビューファイルを作成します。
searchesコントローラ
内で、検索結果を代入したインスタンス変数(@usersと@books)
に対し、each文をつかって1つずつ取り出していきましょう。
<h2>Results index</h2>
<table class="table table-hover table-inverse">
<!--検索対象モデルがUserの時 -->
<% if @range == "User" %>
<tbody>
<% @users.each do |user| %>
<tr>
<td><%= user.name %></td>
</tr>
<% end %>
</tbody>
<% else %>
<!--検索対象モデルがUserではない時(= 検索対象モデルがBookの時) -->
<tbody>
<% @books.each do |book| %>
<tr>
<td><%= book.title %></td>
<td><%= book.body %></td>
</tr>
<% end %>
</tbody>
<% end %>
</table>
これで完成です!お疲れ様でした!
##完成デモ
今回の実装はシンプルなものである為、
モデルが3つ以上の時など臨機応変に修正してください!
閲覧ありがとうございました!
誤字、脱字、知識の誤りなどあればコメントいただけると幸いです!