Railsチュートリアル にユーザー検索を実装してみた

#行ったこと
Railsチュートリアル6.0を完走し、最後に拡張機能としてユーザー検索を実装した
自分の勉強のためにアウトプットしています。

#完成版はこちら
https://damp-spire-94870.herokuapp.com/users?search=e&commit=%E6%A4%9C%E7%B4%A2


#参考記事
https://qiita.com/mochikichi321/items/5c9630c5d87b47130942
https://qiita.com/s-yank/items/964e82bcecaa659caa2d

#手順（チュートリアル14章まで終わっていることが前提）

##1現時点のコード確認

```users/index.html.erb

<% provide(:title, 'All users') %>
<h1>All users</h1>
<%= will_paginate %>

#ここへ検索拡張機能追加予定

<ul class="users">
  <%= render @users %>
</ul>
<%= will_paginate %>
```

```users_controller.rb

class UsersController < ApplicationController
(中略)
  def index
    @users = User.where(activated: true,).paginate(page: params[:page])
#activatedがtrueの物だけ探して、paginateしている
  end
(中略)
end
```

##2まずは、ビューを整える

```users/index.html.erb
<% provide(:title, 'All users') %>
<h1>All users</h1>

<%= will_paginate %>

#検索窓
<%= form_with(url:users_path, :method => 'get',local: true) do |form|  %>
  <%= form.label :ユーザー検索 %>
  <%= form.text_field :search,class:'form-control' %>
  <%= form.submit '検索' , class: "btn btn-primary" %>
<% end %>

 
<ul class="users">
  <%= render @users %>
</ul>

<%= will_paginate %>
```

ここでつまずいたので解説すると、

```Ruby
<%= form_with(url:users_path, :method => 'get',local: true) do |form|  %>
  <%= form.label :ユーザー検索 %>
  <%= form.text_field :search,class:'form-control' %>
  <%= form.submit '検索' , class: "btn btn-primary" %>
<% end %>
```

form_withはform_tagが非推奨になったことから、railsチュートリアルでも利用していたタグ。
`url`,`method`、`local`を指定する。
`method => 'get'`を指定しないと、form_withがデフォルトでmethod post送信なのでうまく処理されないらしい
`local:true`を指定しないと、form_withがデフォルトでremote: trueとなり、送信したデータがAjax通信で処理されます
その場合、検索ボタンを押した時に画面が遷移しないため、indexの一覧画面の情報が更新されなくなってしまう。

classの指定はbootstrapを反映させるためです。

##3コントローラー側
コントローラー側はこちらの記事を参考（マルパクリ）で
https://qiita.com/mochikichi321/items/5c9630c5d87b47130942

```users_controller.rb

class UsersController < ApplicationController
(中略)
  def index
    #条件分岐
    @users = if params[:search]
      #searchされた場合は、原文+.where('name LIKE ?', "%#{params[:search]}%")を実行
      User.where(activated: true).paginate(page: params[:page]).where('name LIKE ?', "%#{params[:search]}%")
    else
      #searchされていない場合は、原文そのまま
      User.where(activated: true).paginate(page: params[:page])
    end
  end
(中略)
end
```

こうなります

```Ruby
where('name LIKE ?', "%#{params[:search]}%")
```

の部分は、SQLの文法で
https://techacademy.jp/magazine/22330
を参考にすると

```Ruby
User.where("name LIKE ?", "%hana%")
```

LIKE句はSQLの検索を行うための演算子
name LIKEと書くことでnameカラムを検索、という意味になる

?は次の引数"%hana%"を受け取る場所になります。最終的にname LIKE "%hana%"という風になるということです。%は任意の文字列を指します。

つまり、nameカラムにhanaを含むレコードを抽出する、という処理になるらしい。

最終的に、

```Ruby
where('name LIKE ?', "%#{params[:search]}%")
```

params[:search]で受け取った文字式展開を受け取り、検索すると言う事になります。

これで実装されるはずですがリファクタリングもしておきます。


##4リファクタリング

```models/user.rb

class User < ApplicationRecord
(中略)
  def self.search(search) #ここでのself.はUser.を意味する
    if search
      where(['name LIKE ?', "%#{search}%"]) #検索とnameの部分一致を表示。#User.は省略
    else
      all #全て表示。#User.は省略
    end
  end
  
  private
(中略)
end
```

```users_controller.rb

class UsersController < ApplicationController
(中略)
  def index
    @users = User.where(activated: true).paginate(page: params[:page]).search(params[:search])
  end
(中略)
end
```

これでform_withを使った検索の実装は終わりです

後日、こちらのテストも書いてみたいと思います。