前提条件
・バージョン rails 6.1.7
・device導入 ・Bootstrap導入
・ユーザー機能実装済(Userモデル)
・投稿機能実装済(Bookモデル)
.検索対象(ユーザーか投稿か)の選択かをプルダウンメニューで選択できること
・完全一致, 前方一致, 後方一致, 部分一致の検索手法をプルダウンメニューで選択できること
・検索後は、検索結果一覧ページを表示します。
ルーティング
get 'searche' => 'searches#search'
モデル
# 検索方法分岐 (nameは検索対象であるusersテーブル内のカラム名)
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
# 検索方法分岐 (titleは検索対象であるbooksテーブル内のカラム名)
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
looksメソッドは、検索方法(完全一致、前方一致、後方一致、部分一致)と検索ワードを元にユーザーを検索します。
完全一致("perfect_match")
: 検索ワードと(ユーザー、本)名が全く同じユーザーを探します。
前方一致("forward_match")
: 検索ワードで始まる(ユーザー、本)名を持つユーザーを探します。
後方一致("backward_match")
: 検索ワードで終わる(ユーザー、本)名を持つユーザーを探します。
部分一致("partial_match")
: 検索ワードを含む(ユーザー、本)名を持つユーザーを探します。
それ以外: 全てのユーザーを返します。
User.where("name LIKE?", "#{word}%")
のような形で、SQLのLIKE検索を使って、条件に一致するものをデータベースから探し出します。
コントローラー作成
searchesコントローラーを作成します。
rails g contoroller searches
アクションの定義
class SearchesController < ApplicationController
before_action :authenticate_user!
def search_result
@range = params[:range]
if @range == "User"
@users = User.looks(params[:search], params[:word])
else
@books = Book.looks(params[:search], params[:word])
end
end
end
before_action :authenticate_user!
ユーザーがログインしていることを確認しています。これにより、ログインしていないユーザーが検索を使用することを防ぎます。
@range = params[:range]
検索範囲(ユーザーまたは本)を@rangeという変数に保存します。
if @range == "User": 検索範囲が"User"かの確認。
@users = User.looks(params[:search], params[:word])
もし範囲が"User"なら、Userモデルのlooksメソッドを使用してユーザーを検索します。
else @books = Book.looks(params[:search], params[:word])
検索範囲が"User"以外("Book")なら、同様にBookモデルのlooksメソッドを使用して本を検索します。
views
検索フォーム
部分テンプレートを作成して検索フォームを作成します。
_search.html.erb
<% if user_signed_in? %>
<div class="search_form">
<%= form_with url: search_result_path, method: :get, local: true 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"],["部分一致","purtial_match"]]) %>
<%= f.submit "検索", class: "btn btn-primary" %>
<% end %>
</div>
<% end %>
<% if user_signed_in? %> :ユーザーがログインしているか確認
<%= form_with url: search_result_path, method: :get, local: true do |f| %>
新たなフォームを作成します。このフォームはsearch_result_pathというURLにデータを送信します。
メソッドはGET、JavaScriptを使用せずに直接HTMLとして送信する設定(local: true)です。
<%= f.text_field :word %>: 検索フィールド表示
<%= f.select :range, options_for_select([['User'],['Book']]) %>
ドロップダウンリストを作成します。"User"または"Book"を選択できます。
同じように(完全一致、前方一致、後方一致、部分一致)ドロップダウンリストを作成。
(例: "完全一致")がユーザーに表示されるテキストで、2つ目の要素(例:"perfect_match")が実際の値(formが送信された時にサーバーに送られる値)です。
検索フォームを好きなページに呼び出す
<%= render 'books/search' %>
検索結果ページ
searchsディレクトリ内にsearch_result.html.erb
を作成
<h2>Book search for "test"</h2>
<table class="table table-hover table-inverse">
<thead>
<tr>
<% if @range == "User" %>
<th>Image</th>
<th>Name</th>
<% else %>
<th>Image</th>
<th>Title</th>
<th>Opinion</th>
<% end %>
<th colspan="3"></th>
</tr>
</thead>
<% if @range == "User" %>
<!-- Userが検索対象の時 -->
<tbody>
<% @users.each do |user| %>
<tr>
<td><%= image_tag user.get_profile_image(50,50) %></td>
<td><%= user.name %></td>
</tr>
<% end %>
</tbody>
<% else %>
<!-- User以外のモデル(Book)が検索対象の時 -->
<tbody>
<% @books.each do |book| %>
<tr>
<td><%= image_tag book.user.get_profile_image(50,50) %></td>
<td><%= book.title %></td>
<td><%= book.body %></td>
</tr>
<% end %>
</tbody>
<% end %>
</table>
userを検索した時には、プロフィール画像・名前を表示します。
userでない時(book)の時は、プロフィール画像・タイトル・内容を表示する。
tableタグ解説
Userが検索対象の場合、タグ内に'Image'と'Name'を表示し、User以外(Book)が検索対象の場合、'Image', 'Title', 'Opinion'を表示します。
ひとこと
ご覧いただきありがとうございます!
一覧ページ等のレイアウト簡単なものなのでもう少し整えてみたいですね。
初心者ですので、間違った部分ありましたら教えてくださいね!