Railsにタグ機能をつける。acts-as-taggable-on使用

## 概要
Railsでgem acts-as-taggable-onを使って、タグ機能を付けました。
私が付けた機能は、新規投稿から、既存のタグ（seedファイルに）を用意しておいて、そこから複数選べるタグ機能です。
下記イメージです。
<img width="598" alt="スクリーンショット 2020-07-16 22.58.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675326/1969c6e0-1c8b-5126-eab4-a65d4921726d.png">
## 環境
Ruby 2.5.7
Rails 5.2.4.2
デザインBootstrap使用

## 実装

① インストール

```Gemfile.
gem 'acts-as-taggable-on', '~> 6.0'
```

```ターミナル.
$ bundle install
```

② テーブル作成

```ターミナル.
$ rails acts_as_taggable_on_engine:install:migrations

$ rails db:migrate
```

③ モデルとコントローラーに追記

```app/models/style.rb
class Style < ApplicationRecord
    acts_as_taggable  #追加
end
```

indexには、タグ一覧とタグを押したときにタグ付けしてあるものを表示。

```app/controllers/styles_controller.rb
def index
    @tags = ActsAsTaggableOn::Tag.all
    # タグの一覧表示
    if params[:tag]
      @styles = Style.tagged_with(params[:tag])
      # タグ検索時にそのタグずけしているものを表示
    else
      @styles = Style.all
    end

def new
    @style = Style.new
    @tags = ActsAsTaggableOn::Tag.all
end

def show
    @style = Style.find(params[:id])
end

def create
    @style = Style.new(style_params)
    @style.user_id = current_user.id
    if @style.save
      flash[:notice] = "スタイルを登録しました"
      redirect_to style_path(@style.id)
    else
      @tags = ActsAsTaggableOn::Tag.all
      render :new
   end
end
# update・destroyは同じような形なので省略します

private

def style_params
      params.require(:style).permit(:name, :user_id, :image, tag_list: [])
      #  tag_list: []　を追記
end

end
```

④ seedファイルに追記
今回は、既存のタグを用意するので、seedファイルを活用。

```db/seeds.rb
# タグ付紐付け(%w()の中に記述)
array = %w(キュート ナチュラル エレガント モード レディースマッシュ メンズマッシュ ショートボブ 内巻きボブ ショートレイヤー ロングレイヤー レイヤー レディース刈上げ メンズ刈上げ メンズカット メンズツーブロック レディースツーブロック モヒカン メンズビジネス 女の子 男の子 学生 ミセス バレイヤージュ メッシュ グラデーションカラー 芸能人 編み込み 結婚式 成人式 卒業式 和装 パーティー カジュアル メイクキュート メイクモード メイクナチュラル メイクエレガント メイク成人式 メンズウルフ レディースウルフ グラデーションボブ 外ハネボブ 前下がり スポーティー グレイヘア インナーカラー イヤリングカラー メンズパーマ レディースパーマ メンズメッシュ メンズカラー)
array.each{ |tag|
  tag_list = ActsAsTaggableOn::Tag.new
  tag_list.name = tag
  tag_list.save
}
```

```ターミナル.
$ rails db:seed
```

⑤ viewに記述

- index.html.erb

```html

<div class="col-xs-12">
   <% @tags.each do |tag| %>
      <%= link_to "#{tag.name}(#{tag.taggings_count})", tag_path(tag.name), class: "label label-default" %>
   <% end %>
</div>
```

- new.html.erb

```html
<%= form_for @style do |f| %>
  <div class="col-xs-12">
・・・・・・・
    <label class="col-sm-12">タグ</label>
      <div class="col-sm-12">
        <% @tags.each do |tag| %>
          <%= f.check_box :tag_list, { multiple: true }, "#{tag.name}", nil %>
          <%= f.label " #{tag.name}(#{tag.taggings_count})", class: "label label-default" %>
        <% end %>
      </div>

      <div class="col-sm-12 text-right">
        <%= f.submit "新規作成", class: "btn btn-danger" %>
      </div>
   </div>
  </div>
<% end %>
```

- show.html.erb

```html
<label class="col-sm-12 my-top">
   <%= raw(@style.tag_list.map { |t| link_to t, tag_path(t), class: "label label-default" }.join(' ')) %>
</label>
```

以上で下記のような感じになります。

- new.html.erb
<img width="598" alt="スクリーンショット 2020-07-16 22.58.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675326/c793fcf0-9d48-1a8c-ed0b-5452b508cd48.png">

- index.html.erb
<img width="178" alt="スクリーンショット 2020-07-16 23.57.32.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/675326/3eb4b6d0-2073-23ac-2586-744ea984944d.png">


indexのtagged_with(params[:tag])では、タグの絞り込みを行っています。タグをクリックするとタグに紐でくデータが表示されます。
 #{tag.name}では、タグ名の表示。#{tag.taggings_count}は、タグの登録数が表示されます。
以上で、実装完了です。

## 補足
本番環境にデプロイ時、acts-as-taggable-onでエラーが出てしまいました。エラーが出た方は、参考にしてもらえればと思います。
タグテーブルの修正が必要なのですが、

```db/migrate/・・・_acts_as_taggable_on_migration.acts_as_taggable_on_engine.rb
t.references :tag, foreign_key: { to_table: ActsAsTaggableOn.tags_table }
```

上記の外部キーを設定しているにも関わらず、

```db/migrate/・・・・_add_missing_unique_indices.acts_as_taggable_on_engine.rb
remove_index ActsAsTaggableOn.taggings_table, :tag_id if index_exists?(ActsAsTaggableOn.taggings_table, :tag_id)
```

外部キーを削除せずにインデックスを削除しようとしているからみたいです。

なので下記のような形にすると動きました。

```db/migrate/・・・・_add_missing_unique_indices.acts_as_taggable_on_engine.rb
# This migration comes from acts_as_taggable_on_engine (originally 2)
if ActiveRecord.gem_version >= Gem::Version.new('5.0')
  class AddMissingUniqueIndices < ActiveRecord::Migration[4.2]; end
else
  class AddMissingUniqueIndices < ActiveRecord::Migration; end
end
AddMissingUniqueIndices.class_eval do
  def self.up
    add_index ActsAsTaggableOn.tags_table, :name, unique: true

    # remove_index ActsAsTaggableOn.taggings_table, :tag_id if index_exists?(ActsAsTaggableOn.taggings_table, :tag_id)
    # 上記をコメントアウト
    if index_exists?(ActsAsTaggableOn.taggings_table, :tag_id) #追加
      remove_foreign_key :taggings, :tags                      #追加
      remove_index ActsAsTaggableOn.taggings_table, :tag_id    #追加
    end
    remove_index ActsAsTaggableOn.taggings_table, name: 'taggings_taggable_context_idx'
    add_index ActsAsTaggableOn.taggings_table,
              [:tag_id, :taggable_id, :taggable_type, :context, :tagger_id, :tagger_type],
              unique: true, name: 'taggings_idx'
  end

  def self.down
    remove_index ActsAsTaggableOn.tags_table, :name

    remove_index ActsAsTaggableOn.taggings_table, name: 'taggings_idx'

    add_index ActsAsTaggableOn.taggings_table, :tag_id unless index_exists?(ActsAsTaggableOn.taggings_table, :tag_id)
    add_index ActsAsTaggableOn.taggings_table, [:taggable_id, :taggable_type, :context], name: 'taggings_taggable_context_idx'
  end
end
```

こちらは、下記を参考にさせてもらいました。
https://teratail.com/questions/224720

開発環境では、問題なかったところでエラーがgemで出たので、焦りました、、、
参考になれば幸いです。