1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Railsで検索バーを設ける〜複数テーブルを結合させて検索を行う

Posted at

はじめに

今回は、投稿データ(Post)を検索バーでキーワード検索を行い、表示させる。また、複数のテーブルを結合させて、その範囲で検索できるように実装していきます。

完成イメージ

※後日掲載予定

環境

MacOS 10.15.7
ruby 2.6.5
Ruby on Rails 6.0.0

執筆者の状況

###テーブル
searchFunction1.png

利用者を「User」、投稿を「Post」、画像を「Image」、都道府県を「Prefecture」(seedデータ)としてテーブルを作成しております。
(テーブルの中身は投稿用に簡略化してます)

リレーションは次の通りです。

user.rb
has_many :posts, dependent: :destory
post.rb
belongs_to :user
belongs_to :prefecture

has_many :images, dependent: :destory


accepts_nested_attributes_for :images, allow_destroy: true
image.rb
belongs_to :post

mount_uploader :image, ImageUploader
prefecture.rb
has_many :posts

このような形になっています。userとimageも紹介してはいるのですが、今回は関わりが無いので説明を省略します。
prefectureはpost(投稿)を複数持っているので、「has_many :posts」としています。
postはprefectureに属しているので、「belongs_to :prefecture」になります。

作業していきます!

###①検索バーの設定〜機能実装

####①-1 検索バーの作成
このようにして検索バーを作成します。

index.html.erb
<%= form_with(url: search_posts_path, local: true, method: :get, class: "rootpageSearchForm") do |form| %>
  <%= form.text_field :keyword, placeholder: "キーワードを入力", id: 'Search_Form', class: "rootpageSearchForm__content" %>
  <%= form.submit "検索", class: "rootpageSearchForm__bottum" %>
<% end %>
index.scss
.rootpageSearchForm {
  width: auto;
  &__content {
    width: 40vw;
    height: 30px;
    color: #000000;
    border-radius: 5px;
    border-color: #008bbb;
  }
  &__bottum {
    margin-left: 0.5vw;
    height: 30px;
    width: 150px;
    border-radius: 20px;
    background-color: #87cefa;
    border: none;
    box-shadow: 0 0 8px gray;
    color: #ffffff;
    -webkit-transition: all 0.3s ease;
    -moz-transition: all 0.3s ease;
    -o-transition: all 0.3s ease;
    transition: all 0.3s ease;
  }
  .rootpageSearchForm__bottum:hover {
    background-color: #00bfff;
  }
}

以上となります。完成イメージはこんな感じです。
searchForm.png

####①-2 searchアクションの作成
routes.rbにsearchアクションを新規で定義します。今回はpostアクションにネストさせた形で定義します。
以下のように定義します。

routes.rb
Rails.application.routes.draw do
  resources :posts do
    collection do
      get 'search'
    end
  end
  下記一部省略...
end

今回、検索のキーワードで該当する投稿を一覧として表示させるので、idが不要なため

collection do
  get 'search'
end

と定義します。

仮にidを必要とする場合(投稿の詳細ページなど)はcollectionではなく、memberを用いて定義します。
collectionとmemberの違いはURLにidが付くか、付かないかの違いです。

collection ・・・ ルーティングにidが付かない。
member ・・・ ルーティングにidが付く。

###①-3 searchメソッドをpostモデルに定義

class Post < ApplicationRecord
  ...上記一部省略
  def self.search(search)
    if search != ""
      Post.where('content LIKE(?) OR title LIKE(?), "%#{search}%", "%#{search}%")
    else
      Post.all
    end
  end
  下記一部省略...
end

whereメソッドを使って、引数に記述した条件を基に、テーブル内の「条件に一致したレコードのインスタンス」を配列の形で取得。

LIKE句を使い、曖昧な文字列を検索するようにしています。

文字列 意味
任意の文字列(空白文字列含む)
_ 任意の1文字

実行例

実行例 意味
where('title LIKE(?)', "a%") aから始まるタイトル
where('title LIKE(?)', "%b") bで終わるタイトル
where('title LIKE(?)', "d_") cが含まれるタイトル
where('title LIKE(?)', "%b") dで始まる2文字のタイトル
where('title LIKE(?)', "_e") eで終わる2文字のタイトル

引数searchは、検索フォームから送信されたパラメーターが入る。
そのため、if search != ""と記述し、検索フォームに何か値が入力されていた場合を条件とする。

検索フォームに何も入力されない(空の状態)で検索ボタンが押されると、引数に渡されるsearchの中身が空になるので、その場合の処理をelse文内で記述。
今回はPost.allとして、全ての投稿を取得して表示させます。

テーブルとのやりとりに関するメソッドはモデルに置くのが基本!

####①-4 コントローラーを記述

posts_controller.rbにsearchアクションを定義します。

posts_controller.rb
class PostsController < ApplicationController
  ...上記一部省略...
  def search
    @posts = Post.search(params[:keyword]).order(created_at: :desc)
  end
  ...下記一部省略...

searchメソッドの引数にparams[:keyword]と記述して、検索結果を渡します。

また、検索結果を投稿が新しい順で並べるため、order(created_at: desc)と記述してます。

####①-5 search.html.erbを作って、検索結果を表示させる
あとは、検索結果画面を表示させるsearch.html.erbを作って完了です。

search.html.erb
<div class="wrapper">
  <% @posts.each do |post| %>
    <div class='contents row'>
    ...以下省略...
  <% end %>
</div>

####①-6 完成!
これで、検索バー並びにキーワード検索により、検索結果を表示できるようになりました。
ここまでの設定では、Postテーブルの「content(投稿文)」と「title(投稿タイトル)」が検索対象になっている状態です。

###② 他のテーブルを結合させて、検索対象に追加する。

今回、都道府県名でも検索できるように、検索対象にPrefectureテーブルの「name(都道府県名)」を追加していきたいと思います。

postモデルに記述を追加していきます。

class Post < ApplicationRecord
  ...上記一部省略
  def self.search(search)
    if search != ""
      Post.joins(:prefecture).where('content LIKE(?) OR title LIKE(?) OR prefectures.name LIKE(?)', "%#{search}%", "%#{search}%", "%#{search}%")
    else
      Post.all
    end
  end
  下記一部省略...
end

prefectureテーブルも検索対象にするために、joins(:prefecture)として追加しています。
joinメソッド複数のテーブルを1つに結合したいときに使うメソッドです。
今回の場合は、postテーブルとprefectureテーブルを結合させて、1つのテーブルとして扱います。

whereメソッドの引数の部分には、OR prefectures.name LIKE(?)'を追加して都道府県名を検索対象に指定しています。この分の"%#{search}%"も1つ追加して完了です。

#最後に
初学者のため、間違い等ありましたらご指摘いただけますと幸いです。
最後までご覧いただきありがとうございました。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?