Railsアプリでの検索フォームの作り方
投稿を検索する機能の作り方です。
こういうやつですね。
ルーティングを設定
まずはルーティングを設定します。
resourcesの7種類には含まれないアクションを作るので、collectionを使います。config/routes.rb
に以下のように記述します。
Rails.application.routes.draw do 略 resources :posts do collection do get "search" end end end
これで、postsコントローラーのsearchアクションへのルーティングが設定できました。
rails routesで調べてみると、search_postsという名前がついています。
ビューに検索フォームを作成
パスが作成できたので、ビューファイルにフォームを作ります。
<%= form_with url: search_posts_path, local: true, method: :get, class: "search-form" do |f| %> <%= f.text_field :keyword, placeholder: "投稿を検索する", class: "search-input" %> <%= f.submit "検索", class: "search-btn" %> <% end %>
検索するワードには、:keywordという名前をつけておきました。
form_withはデフォルトではAjax通信を行うので、local: trueの記述でAjaxを無効にする必要があります。そして、HTTPメソッドはgetに変更しておきます。
コントローラーにsearchアクションを作成
入力されたキーワードで検索した投稿を受け取るため、app/controllers/posts_controller.rb
でsearchアクションを定義します。
@posts = Post.search(params[:keyword])
しかしsearchというメソッドは存在しないので、自分で定義する必要があります。
モデルでsearchメソッドを定義
入力されたキーワードを含む投稿をデータベースから検索するメソッドを、モデルで定義します。データベースに関するメソッドはモデルで定義する、という意識が重要です。
class Post < ApplicationRecord def self.search(keyword) if keyword != "" Post.where('text LIKE(?)', "%#{keyword}%") else Post.all end end end
クラスメソッドなので、self.method()というようにメソッド名の前にself.をつけて定義します。
入力されたキーワードが空であるかを判断し、空だった場合は全ての投稿を返すようにしています。
実際に検索をするのに必要なのが、LIKE句というものです。
モデル.where("カラム名 LIKE(?)", "検索したい文字列")
という感じで使います。
検索したい文字列は、"%"と"_"を使って表現します。
"%"は任意の文字列、"_"は任意の一文字を意味しています。
例えば"_#{keyword}%"とすると、keywordの前に一文字、後ろに0文字以上の文字が並ぶ文字列を探してきます。
よって上の例で言えば、postsテーブルの中で、textというカラムの値にkeywordを含んでいるレコードを全て取得してくる、ということになります。
検索結果を表示するビューを用意
最後に、検索して得られた結果を表示するためのビューファイルを用意したら完了です。
今回は、postsコントローラーのsearchアクションに対応するビューが必要なので、app/views/posts/search.html.erb
というファイルを作成します。
まとめ
- 検索機能をつけるにはモデルでsearchメソッドを定義
- 文字列の検索にはLIKE句