[Rails]本にカテゴリタグを追加し検索する

## 行いたいこと
- 本の投稿時にカテゴリタグを追加する
- カテゴリタグで検索が出来る
## 環境
- Ruby3.1.2
- Rails6.1.7
- device、bootstrap導入済み
- Bookモデル作成済み


# 1.カラムの追加
Bookモデルにタグを保存するために新しくカラム`tag`を作成
```
# rails g migration add追加したいカラム名To追加したいモデル名 追加したいカラム名:データ型
  rails g migration addTagToBook tag:string
```
```作成日_add_tag_to_book.rb
class AddTagToBook < ActiveRecord::Migration[6.1]
  def change
    add_column :books, :tag, :string
  end
end
```
```
$ rails db:migrate
```

# 2.コントローラー作成、バリデーション設定

#### バリデーション、ストロングパラメータの設定
```models/book.rb
validates :tag,presence:true
```
books_controllerのストロングパラメータに`:tag`を追加
```books_controller.rb
  private

  def book_params
    params.require(:book).permit(:title,:body,:rating,:tag)#tagを追加
  end
```

#### TagSearchesコントローラーを作成
```
$ rails g controller TagSearches
```
コントローラーへの記述は以下の通り
今回は部分一致で検索を実施
@modelはresultのviewを他から流用しており、そこで@modelを使用しているため指定
searchとしての処理には不必要であり、後述のviewで使用しないなら削除してOK
```layouts/_tag_search.html.rb
class TagSearchesController < ApplicationController
  def search
    @model = Book #search機能とは関係なし
    @word = params[:word]
    @books = Book.where("tag LIKE?","%#{@word}%")
    render "searches/result"
  end
end
```
# 3.viewページの作成
#### 投稿フォームへの追加
tagを追加するためのtext_fieldを作成
```views/books/_form.html.erb
  <div class="form-group">
    <%= f.label :Tag %>
    <%= f.text_field :tag, class: 'form-control book_tag' %>
  </div>
```
#### タグ検索用の検索ボックスの作成
```views/layouts/_tag_search.html.erb
<% if user_signed_in? %>
  <div class="search_form">
    <%= form_with url: tag_search_path, local: true,method: :get do |f| %>
      < %= f.text_field :word %>
      <%= f.submit "タグ検索" %>
    <% end %>
  </div>
<% end %>

```
#### 検索結果の表示
今回他で作成した検索結果表示ページを流用
`book.tag`で保存されたタグを呼び出す
```views/searches/_result.erb
<h2><%= @model %>s search for "<%= @word %>"</h2>
# Books search for "<%= @word %>"と記載すれば@model不要

<table class="table table-hover table-inverse">
　　　　　　　〜省略〜
    <thead>
      <tr>
        <th></th>
        <th>Title</th>
        <th>Opinion</th>
        <th>Tag</th>
      </tr>
    </thead>
    <% @books.each do |book| %>
    <tbody>
      <tr>
        <td><%= image_tag book.user.get_profile_image, size:'50x50' %></td>
        <td><%= book.title %></td>
        <td><%= book.body %></td>
        <td><%= book.tag %></td> #追加！
        <td><%= render "favorites/nice", book: book %></td>
        <td>コメント数：<%= book.book_comments.count %></td>
        <td class ="px-0"><%= render "books/rating", book: book %></td>
      </tr>
    </tbody>
    <% end %>
  <% end %>
</table>
```
またindexにも同様に **<%= book.tag %>** で表示

```views/books/_index.erb
 <% books.each do |book| %>
      <tr>
        <td><%= link_to(book.user) do %>
          <%= image_tag book.user.get_profile_image, size:'50x50' %>
          <% end %>
        </td>
        <td class ="px-0"><%= link_to book.title,book %></td>
        <td><%= book.body %></td>
        <td><%= book.tag  %></td> #追加
        <td id="js-book_favorite_<%= book.id %>">
```
完成！（今回作成したのはタグ検索の部分のみ)
![スクリーンショット.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2950107/0d072415-a98f-206e-2389-e3fa6920fa6f.png)


## 応用
#### タグにリンクを付与し、クリックすると、そのタグ名で検索を行う

https://qiita.com/Auk10/items/f6e3f2e59c8fd41db472

上記記事にも投稿しましたが、`link_to〜_path( )`の( )に値を設定することで、任意の値を一緒に送信することが出来る
これを活用し
```.rb
<%= link_to book.tag, tag_search_path(word: book.tag) %>
```
とリンクを作成することで、送信時一緒に`:word`として`book.tag`が送られる
#### 投稿済みの本に設定してあるタグから検索する方法
f.text_fieldを削除し、下記のコードを追加
```_tag_searches_controller.rb
#〜省略〜
<%= f.text_field :word %> #削除
#下２行追加
<% tag = Book.select(:tag).distinct %> 
<%= f.collection_select(:word, tag, :tag, :tag) %>
#〜省略〜
```
`tag = Book.select(:tag).distinct`
本の投稿からtagカラムだけを抜き出し、`distinct`で重複を削除
※`distinct`を使用しないと下記のように全件表示される(空欄はtag未設定の投稿)
![スクリーンショット.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2950107/e85aed25-5881-9ec7-9397-4f9d081adb9b.png)
`f.collection_select(:word, tag, :id, :tag)`
collection_selectはRailsドキュメントを参照すると
[Railsドキュメント(collection_select)](https://railsdoc.com/page/collection_select)
>f.collection_select(メソッド名, 要素の配列, value属性の項目, テキストの項目, オプション={}, HTML属性={} or イベント属性={})

とある。つまり
- 第1引数`:word`　メソッド名。送信したい項目名と言い換えればわかりやすいか
- 第2引数`tag`参照するデータ。今回はひとつ上に書いた`tag = Book.〜`のtagを指定。Book.all等も指定できる
- 第3引数`:tag`第２引数のデータの中で、送信するデータのカラムを指定。tagカラムの内容を送りたいので`:tag`
- 第4引数`:tag`テキストの項目。第２引数のデータの内実際に選択肢として表示したい物。tagカラムの中身を表示したいので`:tag`

※この場合下記の様に、コントローラーは完全一致で検索するように修正したほうが的確
```tag_search_controller.rb
@books = Book.where(tag: @word)
```
以上で投稿された本のタグで検索が行えるようになる
![スクリーンショット 2022-12-09 18.44.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2950107/adfa4cc4-b78d-6d47-4caa-3891358cb11b.png)