検索機能の実装

**index.html.erbを編集する**

検索窓と検索ボタンを作成する。
app/views/tweets/index.html.erb
```ruby
<%= form_with(url: search_tweets_path, local: true, method: :get, class: "search-form") do |form| %>
  <%= form.text_field :keyword, placeholder: "検索する", class: "search-input" %>
  <%= form.submit "検索", class: "search-btn" %>
<% end %>
```

**searchアクションのルーティングを設定する**
*collection*と*member*
collectionとmemberは、ルーティングを設定する際に使用できます。
これを使用すると、生成されるルーティングのURLと実行されるコントローラーを任意にカスタムできる。

collectionはルーティングに:idがつかない、memberは:idがつくという違いがある。
（詳細ページのような:idを指定して特定のページにいく必要がない場合はcollectionを使用してルーティングを設定する）

【例】collectionで定義した場合
```ruby
Rails.application.routes.draw do
  resources :tweets do
    collection do
      get 'search'
    end
  end
end
```


【例】memberで定義した場合
```ruby
Rails.application.routes.draw do
  resources :tweets do
    member do
      get 'search'
    end
  end
end
```

**routes.rbを以下のように編集する**
config/routes.rb
```ruby
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メソッドとする。

**whereメソッド**
モデルが使用できる、ActiveRecordメソッドの1つ。

【例】whereメソッド
```ruby
モデル.where('検索対象となるカラムを含む条件式')
```

複数のカラムを１つの検索フォームだけで検索したい場合は下記のようにすればできる。
```ruby
適切なオブジェクト名.where(['検索したいカラム名 ? OR 検索したいカラム名 LIKE ? OR 検索したいカラム名 LIKE ?', "%#{search}%", "%#{search}%", "%#{search}%"])
```
検索したいカラムが３つある場合は、"%#{search}%"も３つつければ１つのフォームで複数カラムまたいで検索できる！！

**LIKE句**
LIKE句は、曖昧（あいまい）な文字列の検索をするときに使用するもので、whereメソッドと一緒に使う。

app/models/tweet.rb
```ruby
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
```

**searchアクションをコントローラーに定義する**
app/controllers/tweets_controller.rb
```ruby
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")
  end

  def new
    @tweet = Tweet.new
  end

  def create
    Tweet.create(tweet_params)
  end

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

  def edit
  end

  def update
    tweet = Tweet.find(params[:id])
    tweet.update(tweet_params)
  end

  def show
    @comment = Comment.new
    @comments = @tweet.comments.includes(:user)
  end

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

  private
  def tweet_params
    params.require(:tweet).permit(:image, :text).merge(user_id: current_user.id)
  end

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

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

**検索結果画面のビューを作成**
app/views/tweetsディレクトリの配下にsearch.html.erbを作成し
検索結果を表示するように記述する。

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