Railsアプリケーションで投稿検索機能を実装する(whereメソッド)


アプリ: ラーメン屋の写真や情報を友達と共有できるSNS
Ruby: 2.6.5
Rails: 5.2.0

viewに検索フォームを設置する

form_withを使って、検索ワードをposts_controllerのsearchアクションに渡します。

app/views/layouts/_header.html.erb
・
・
・
<div class="post_search">
  <%= form_with url: search_posts_path, method: :get, local: true do |f| %>
    <%= f.text_field :search, class: 'form-control', placeholder: "キーワード検索"  %>
    <%= f.button :type => "submit" do %>
      <i class="fas fa-search"></i>
    <% end %>
  <% end %>
</div>
・
・
・

ルーティング

routes.rb を下記のようにすることで、
/posts/searchというURL(search_posts_path)にgetリクエストを送ることでposts_controllerのsearchアクションにルーティングされます。

config/routes.rb
~
~
resources :posts, only: [:new, :create, :edit, :show, :update, :destroy] do
  get :search, on: :collection
end
~
~

posts_controller

検索ワードに合致する投稿を@postsで定義。

app/controllers/posts_controller.rb
~
~
def search
  @section_title = "「#{params[:search]}」の検索結果"
  @posts = if params[:search].present?
             Post.where(['shop_name LIKE ? OR nearest LIKE ?',
                        "%#{params[:search]}%", "%#{params[:search]}%"])
                 .paginate(page: params[:page], per_page: 12).recent
           else
             Post.none
           end
end
~
~

params[:search]でform_withから渡された検索ワードを受け取ります。
whereメソッドはテーブル内から条件に一致したレコードをすべて返します。
(検索ワードがない場合はPost.noneとし、投稿を取得しないようにしました。)

whereメソッド

whereメソッドでは下記のように

モデル名.where('カラム名 = ?', "値")

第一引数に ? を(プレースホルダーと呼ぶ)、第二引数に条件の値を入れることがあります。
このような書き方をすることで、SQLインジェクションというデータベースのデータを不正に操作する攻撃を防ぐことができるそうです。

whereの第二引数には下記のように

"%#{params[:search]}%"

検索ワードの前後に % を置いています。
こうすることで、「空白文字を含む任意の複数文字列」が検索ワードの前後に含まれても
その文字列を持つレコードを返すことができます。

%二郎%
→ 「二郎」「ラーメン二郎」「つけ麺二郎」「ラーメン二郎八王子店」「二郎歌舞伎町店」
 どれも該当する。

%二郎
→ 「二郎」「ラーメン二郎」「つけ麺二郎」は該当するが、
 「ラーメン二郎八王子店」「二郎歌舞伎町店」は該当しない。

下記のように書くことでshop_nameとnearestという2つのカラムから
検索ワードに該当する文字列を検索し、レコードを返します。

Post.where(['shop_name LIKE ? OR nearest LIKE ?',
            "%#{params[:search]}%", "%#{params[:search]}%"])

あとは@postsをapp/views/posts/search.html.erbで表示させるようにしてください。

こんな感じ

参考

【Rails】1つの検索フォームで複数カラムをまたいで検索する方法
【Rails】whereメソッドを使って欲しいデータの取得をしよう!