1
5

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.

検索機能

Last updated at Posted at 2020-03-09

##searchアクション
7つのアクション以外のsearchアクションという命名でアクションを定義します。
7つのアクション以外でルーティングを定義する方法は、collectionとmemberというものがあります。
【例】今回はモデル名をTweet、Comment、Userがあるとします。

app/views/tweets/index.html.erb
<%= form_with(url: search_tweets_path, local: true, method: :get, class: "XXXX") do |form| %>
  <%= form.text_field :keyword, placeholder: "投稿を検索する", class: "YYYY" %>
  <%= form.submit "検索", class: "ZZZZ" %>
<% end %>
〜省略〜

検索の入力欄とボタンには、フォームを使います。
##collectionとmember
collectionはルーティングに:idがつかない、memberは:idがつく。という違いがあります。


【例】collectionで定義した場合

Rails.application.routes.draw do
resources :tweets do
collection do
get 'search'
end
end
end


【例】memberで定義した場合

Rails.application.routes.draw do
resources :tweets do
member do
get 'search'
end
end
end

今回の検索機能の場合、詳細ページのような:idを指定して特定のページにいかない使用にするので、collectionを使用してルーティングを設定してみます。
【例】

```config/routes.rb
Rails.application.routes.draw do
  devise_for :users
  root to: 'tweets#index'
  resources :tweets do
    resources :comments, only: :create
    collection do
      get 'search'
    end
  end
  resources :users, only: :show
end

##searchメソッドを定義
モデルにテーブルから検索するためのsearchメソッド定義していきます。
検索したキーワードが含まれている投稿を取得するために、whereメソッドとLIKE句を利用します。
##whereメソッド
モデル.where(条件)のように引数部分に条件を指定することで、テーブル内の条件に一致したレコードのインスタンスを配列の形で取得できます。
引数の条件には、「検索対象となるカラム」を必ず含めて、条件式を記述します。
【例】

モデル.where('検索対象となるカラムを含む条件式')

条件式には'カラム名 > 5'やキーバリューの形でカラム名: 値などの記述が可能です。
対象のカラムに条件と一致する値を持つレコードを全て取得します。
whereメソッドを連続して記述することによって、複数の条件に一致したレコードを取得することもできます。
【例】

Tweet.where('id < 5')
Tweet.where('id < 5').where(user_id: 1)

上記の記述でも取得できます。
##LIKE句
検索機能にはこのwhereメソッドに加えてLIKE句を使用します。
LIKE句は、曖昧な文字列の検索ができるもので、whereメソッドと一緒に使います。
例えば、1文字目に'a'という文字列が入ったデータや最後の文字に'b'が入っているデータ、文字列の途中に'c'が入ったデータなどを検索したい時に、曖昧文字列というものを使って検索できます。
##曖昧文字列
| 文字列 | 意味 |
|:-----------|------------:|:------------:|
| % | 任意の文字列(空白文字列含む) |
| _ | 任意の1文字 |
##実行サンプル
| 実行例 | 詳細 |
|:-----------|------------:|:------------:|
| where('title LIKE(?)', "a%") | aから始まるタイトル |
| where('title LIKE(?)', "%b") | bで終わるタイトル |
| where('title LIKE(?)', "%c%") | cが含まれるタイトル |
| where('title LIKE(?)', "d_") | dで始まる2文字のタイトル |
| where('title LIKE(?)', "_e") | eで終わる2文字のタイトル |
【例】

app/models/tweet.rb
class Tweet < ApplicationRecord
  validates :text, presence: true
  belongs_to :user
  has_many :comments

  def self.search(search)
    return Tweet.all unless search
    Tweet.where('text LIKE(?)', "%#{search}%")
  end
end

もし、引数で渡されるsearchの中身に何もなければ全ての投稿を取得できるようにしています。
そのため、unless文を使ってreturn Tweet.all unless searchと記述しています。
unless文は条件式が偽である場合にだけ処理を実行するという意味です。

実行する処理  unless 条件式

ちなみにif文でも実行できます。

app/models/tweet.rb
class Tweet < ApplicationRecord
  validates :text, presence: true
  belongs_to :user
  has_many :comments

  def self.search(search)
    if search
      Tweet.where('text LIKE(?)', "%#{search}%")
    else
      Tweet.all
    end
  end
end

ですがunless文で記述したほうがコードがすっきりしますね。
##searchアクションをコントローラーに定義
コントローラーにsearchアクションを定義します。

app/controllers/tweets_controller.rb
class TweetsController < ApplicationController
  before_action :set_tweet, only: [:edit, :show]
  before_action :move_to_index, except: [:index, :show, :search]

  def index
    @tweets = Tweet.includes(:user).order("created_at DESC").page(params[:page]).per(5)
  end

〜省略〜

 def search
    @tweets = Tweet.search(params[:keyword])
  end

 def set_tweet
    @tweet = Tweet.find(params[:id])
  end

  def move_to_index
    redirect_to action: :index unless user_signed_in?
  end
end

Tweetモデルに書いたsearchメソッドを呼び出しています。seachメソッドの引数にparams[:keyword]と記述して、検索結果を渡しています。
また、未ログイン状態にトップページへリダイレクトされてしまうことを回避するため、before_actionのexceptオプションに:searchを追加しています。
##検索結果画面のビューを作成
search.html.erbを作成します。
【例】

app/views/tweets/search.html.erb
<%= form_with(url: search_tweets_path, local: true, method: :get, class: "XXXX") do |form| %>
  <%= form.text_field :keyword, placeholder: "投稿を検索する", class: "YYYY" %>
  <%= form.submit "検索", class: "ZZZZ" %>
<% end %>
<div class="AAAA">
  <% @tweets.each do |tweet| %>
    <%= render partial: "tweet", locals: { tweet: tweet } %>
  <% end %>
</div>

今回はすでにrenderしてあることにしています。

1
5
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
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?