Rails 検索機能の付け方

# まえがき
今回の、モデルに新しいメソッドを定義し、7つのアクション以外のものを使うというのはどうやら非推奨みたいです。ただし、こちらの方が私的には簡単に作ることができましたので共有させていただきます。
慣れない点がありますので間違い等がありましたらご指摘いただけると嬉しいです。
# 目次
・検索フォームの作成
・searchアクションのルーティング設定
・searchメソッドをモデルに定義
・searchアクションをコントローラーに定義
・検索結果画面のビューファイルを作成

# 検索フォームの作成
まずは検索フォームを付けていきます。今回はform_withを使って書きます。書き方は以下の通りです。

```ruby:search.html.erb
<%= form_with(url: search_sample_path, local: true, method: :get, class: "search-form") do |form| %>
  <%= form.text_field :keyword, placeholder: "投稿を検索する", class: "search-input" %>
  <%= form.submit "検索", class: "search-btn" %>
<% end %>
```


一つずつ説明していきます。まずurlと指定してある部分はこの後設定する、searchのルーティングで設定されるplefixを書きます。
plefixをパスとして書く時は文字の最後に**_path**をつけるような書き方をします。
plefixはターミナル上でrails routesというコマンドを入力したときに一番ひだりに書いてあるものです。

次に**local:true**ですが、form_withでは何を指定しなくてもremote: trueになるようなのですが、
remote: trueではXMLHTTPRequestオブジェクトリクエストを自動で送信するので、無効化する為にlocal: trueを指定してあげます。remote:trueだと、非同期通信が発動してしまい、画面が遷移しないようです。
ちなみにXMLHTTPRequestオブジェクトとは
>XMLHttpRequest (XHR) は、JavaScriptなどのウェブブラウザ搭載のスクリプト言語でサーバとのHTTP通信を行うための、組み込みオブジェクト（API）である。

ということらしいです。簡単にいうと、非同期なデータ通信をするためのAPIです。
今後Ajaxを使う予定がある人は覚えておいても損はないかもしれません。
ちなみにAjaxは（Asynchronous JavaScript + XML）の略です。
**method: get**は、フォーム送信時のHTTPメソッド（verb）を指定します。
通常は:getや:postを指定するようです。

# searchアクションのルーティング設定

```ruby:routes.rb

Rails.application.routes.draw do
  devise_for :users
  root to: 'samples#index'
  resources :samples do
    resources :comments, only: :create
    collection do
      get 'search'
    end
  end
  resources :users, only: :show
end
```
今回はコメント機能の検索をかけるので、samplesコントローラーとcommentsコントローラーがネスト構造になっていることに注意してください。
**collection do**とはidを付けない書き方です。
今回は検索をするときに詳細の情報は必要ないのでid情報は付けません、もしid情報を付けたい時は**member do**というものがあるのでそちらを使いましょう。

# searchメソッドをモデルに定義
先ほどルーティングにsearchを設定したので今度はモデルにメソッドを定義していきます。現時点だと、**.search**というメソッドは使うことができませんが、モデルで設定することにより、コントローラーで使用することができるようになります。

```ruby:sample.rb
 def self.search(search)
    return Sample.all unless search
    Sample.where('title LIKE(?)', "%#{search}%")
  end
```

今回はtitleで検索をかけていきます。
モデルの中でメソッドを定義する際に、メソッド名の頭に**self.**を付けるとコントローラーで使える**クラスメソッド**という物になります。

上記で**LIKE句**と**whereメソッド**が出てきました
簡単に説明すると**LIKE句**とは、曖昧検索と言われる物に使われるもので、前方一致や後方一致などを指定するときに使います。
**whereメソッド**とは、モデル.where(条件)のように引数部分に条件を指定することで、テーブル内の条件に一致したレコードのインスタンスを配列の形で取得できます。そして今回は条件式に前述したLIKE句を使っています。
ちなみに上記の記述方法をif文を使い、よりわかりやすく書くと下記のようになります。

```ruby:sample.rb
def self.search(search)
    if search
      Sample.where('title LIKE(?)', "%#{search}%")
    else
      Sample.all
    end
  end
```

Sampleテーブルから曖昧検索をかけて絞るのか、全てを出すのかという簡単な式を作ることができます。

# searchアクションをコントローラーに定義
次はコントローラーにアクションを設定し先ほど定義したsearchメソッド使っていきます。

```ruby:sample_controller.rb
 def search
    @sample = Sample.search(params[:keyword])
  end
```

`params[:keyword]`と書くことで、formで入力した、**:keyword**を取得することができます。
もしparamsのなかに何が入っているかを確認したい時は

```ruby:sample_controller
def search
    binding.pry
    #このように記述する
    @sample = Sample.search(params[:keyword])
  end
```

このように**binding.pry**を起動させ、一度ターミナルでparamsと打って、paramsのなかを確認してみると良いでしょう。
今回はparams[:keyword]にはフォームで入力した文字が入るようになっています。

```ruby:search.html.erb
# 検索結果画面のビューファイルを作成
<%= form_with(url: search_samples_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">
  #renderを繰り返し出力する
  <% @sample.each do |sample| %>
    <%= render partial: "sample", locals: { sample: sample } %>
  <% end %>
</div>
```


このビューファイルではrenderを用いて、効率よく投稿ができるような記述をしています。
ビューファイルで使うrenderは部分テンプレートのことで、
`<%= render partial: "sample", locals: { sample: sample } %>`
と記述をすることで、**_sample.html.erb**というファイルを読み込むことができます。

`locals: { sample: sample }`はsampleというeach文で定義した変数を部分テンプレートでなんという変数で扱うかという意味です。右側が、each文で定義した変数で、左側のsampleが部分テンプレート先で扱う変数です。

#あとがき
あとは、部分テンプレート先で検索結果をどのように表示したいかを記述すれば終了です。
はじめにも書きましたが、7つのアクション以外のものを使って検索機能を作るということは本来推奨されていない方法なので、7つのアクションのみで実装する方法も調べてみてください。
この先インクリメンタルサーチを実装したりするかどうかはまた少し工夫が必要になってきますが、ベースは今回記述した検索機能になります。
この記事が検索機能実装でつまずいてしまった人の助けになれれば幸いです。
ではでは！！