acts-as-taggable-on と Tagit.jsを使ったオートコンプリート機能の作成

## 完成系
![スクリーンショット (26).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/169545/affff9cb-8bc0-8854-00a7-e342447d09ea.png)


## 開発環境
```
ubuntu(WSL)
Rails 6.0.2
Ruby 2.5.1
```

## 事前準備
- タグ機能の作成
- 投稿機能の作成（CRUD）
タグ機能の作成に関しては[こちら](https://qiita.com/Dexctersu/items/900bf9f0ee0d8f7b9b11)を参考にしてください。


## Tagitの導入
下記のコマンドを実行して、`vendor/assets`に配置してください。
`vendor/assets`がない場合は自分で作ってください。

```
curl https://raw.githubusercontent.com/aehlke/tag-it/master/js/tag-it.js -o vendor/assets/javascripts/tag-it.js

curl https://raw.githubusercontent.com/aehlke/tag-it/master/css/jquery.tagit.css -o vendor/assets/stylesheets/jquery.tagit.css

curl https://raw.githubusercontent.com/aehlke/tag-it/master/css/tagit.ui-zendesk.css -o vendor/assets/stylesheets/tagit.ui-zendesk.css
```

Jquryを使うので`jqury-ui-rails`をGemfileに追加下ください。

```Gemfile.
gem 'ransack'
gem 'acts-as-taggable-on', '~> 6.0'
gem 'jquery-ui-rails' #追加
```
TagitとJquryUiを読み込むため、`application.js`と`application.scss`に以下を追加下ください。
とりあえず全て載せておきます。

```application.js
//= require jquery #追加
//= require rails-ujs　#追加
//= require popper
//= require turbolinks　#追加
//= require_tree .　#追加
//= require bootstrap
//= require activestorage
//= require jquery-ui/widgets/autocomplete　#追加
//= require tag-it　#追加
```

```application.scss
/*
 *= require_tree . #追加
 *= require jquery.tagit #追加
 *= require tagit.ui-zendesk #追加
 *= require_self #追加
*/
```
テキストボックスを作ります。
form_forブロック内に任意のidをつける。
`f.text_field`にidをつけると二つテキストフィールドができてしまうので`.form-group`にidをつけています。

```views/micropost/_form.html.slim
= form_with model:  micropost, local: true do |f|
  = render 'shared/error_messages', object: f.object
 
  .form-group id="micropost-tags"
    = f.label :tag
    //タグの入力・保存表示
    //= f.text_field :tag_list, value: @micropost.tag_list.join(","), class: "form-control"

```

tagitの呼び出し


```assets/javascripts/microposts.js 
$(document).on('turbolinks:load', function () {
  return $('#micropost-tags').tagit({
  });

```

## タグの保存

現状だとname属性が同じなので`singleField`を有効にしてname属性を変更します。
先ほど書いた`microposts.js`に追加します。

```assets/javascripts/microposts.js 
$(document).on('turbolinks:load', function () {
  $('#micropost-tags').tagit({
    fieldName: 'micropost[tag_list]',
    singleField: true,
  });
```

inputフィールドが`<input type="hidden" style="display:none;" value="Ruby,Python" name="micropost[tag_list]">`
コントローラのパラメータに`:tag_list`を追加してください。


```app/controllers/microposts_controller.rb 
 def micropost_params
      params.require(:micropost).permit(:title, :content, { images: [] }, :tag_list)
 end
```

## 編集画面でタグの表示をする
gonを使ってrailsからjavascriptに渡します。
`Gemfile`に以下を追加かしてください

```Gemfile.
gem 'gon'
```

viewに以下を追加してください。

```views/layouts/application.html.slim
    //= include_gon(:init => true) #こっちで上手くいく場合もあります
    = Gon::Base.render_data
    = javascript_include_tag 'application', 'data-turbolinks-track': 'reload'
```

投稿に含まれているタグを取得します。

```app/controllers/microposts_controller.rb 
before_action :set_micropost_tags_to_gon, only: [:edit]

def set_micropost_tags_to_gon
     gon.micropost_tags = @micropost.tag_list
end
```
Tag-itのcreateTagで追加。
先ほど書いた`microposts.js`に追加します。

```assets/javascripts/microposts.js 
$(document).on('turbolinks:load', function() {
  var i, len, ref, results, tag;
  $('#micropost-tags').tagit({
    fieldName: 'micropost[tag_list]',
    singleField: true
  });
  if (gon.micropost_tags != null) {
    ref = gon.micropost_tags;
    results = [];
    for (i = 0, len = ref.length; i < len; i++) {
      tag = ref[i];
      results.push($('#micropost-tags').tagit('createTag', tag));
    }
    return results;
  }
});
```
これで編集画面で既存タグが表示されると思います。

## オートコンプリート

タグリストにあるタグを全て取得します。

```app/controllers/microposts_controller.rb
 before_action :set_available_tags_to_gon, only: [:edit]

 def set_available_tags_to_gon
      gon.available_tags = Micropost.tags_on(:tags).pluck(:name)
 end
```

gonを`availableTags`に渡します。
省略の部分は先ほどと同じです。

```assets/javascripts/microposts.js
$(document).on('turbolinks:load', function () {
  var i, len, ref, results, tag;
  $('#micropost-tags').tagit({
    fieldName: 'micropost[tag_list]',
    singleField: true,
    availableTags: gon.available_tags,
  });
省略
```
これでできると思います。

### おわりに
間違いがありましたら編集リクエストまたはコメントお願いします。

### 参考文献
- [acts-as-taggable-on と jQUery Tag-it でタグ付け機能作成](https://qiita.com/tyamagu2/items/75eeaa8ef208385aa341)