【Rails】acts-as-taggable-on と jQuery で実装！超簡易版サジェスト機能！

# 実装内容
- 投稿された記事をタグ検索できるようにしよう！ というのが主な目的。
- gemの`acts-as-taggable-on`を使って、記事を投稿する際にタグもDBに保存する。
（今回はサジェスト機能実装がメインなので詳細は割愛。タグ機能実装については
[Rails | acts-as-taggable-on を使ったタグ機能の実装 | 備忘録](https://qiita.com/ddgg7755/items/e1caa8b73d118822a0a2)と
[Railsのタグ機能の実装（gem：acts-as-taggable-on）]
(https://www.blograils.com/posts/rails-actsastag)を参考にしました）

- jQuery UIを使ってDBに保存しているタグをもとにサジェスト機能を作成。
 
[![Image from Gyazo](https://i.gyazo.com/0f309c02faf9fa0e5867f81d50163b66.gif)](https://gyazo.com/0f309c02faf9fa0e5867f81d50163b66)

# 開発環境
- Ruby 2.5.1
- Rails 5.2.3
- Haml・Sass記法

# 実装手順
## gemのインストール
```
gem 'acts-as-taggable-on', github: 'mbleigh/acts-as-taggable-on', branch: 'master'
gem 'jquery-ui-rails'
gem 'jquery-rails'
```
記述が終わったら、ターミナルで`bundle install`も！！

## application.jsに追記
```javascript:application.js
//= require jquery
//= require jquery-ui/widgets/autocomplete
```
jQueryを使えるようにします。

## application.scssに追記
```scss:application.scss
@import "jquery-ui/autocomplete";
@import "jquery-ui/theme";
@import "jquery-ui/menu";
```
今回はSCSSですが、CSSだと`*= require jquery-ui`という一文になるそうです。

## routes.rbに追記
```ruby:routes.rb
Rails.application.routes.draw do
  root 'reviews#index'
  resources :reviews do
    collection do
      get 'search'
      get 'autocomplete' # この１行を追記
    end
  end
end
```
この記述をすることによって、以下のようにルーティングが設定できました。
[![Image from Gyazo](https://i.gyazo.com/e715ff78718d24403e36d6f4a7fbd374.png)](https://gyazo.com/e715ff78718d24403e36d6f4a7fbd374)

## controller.rbに追記
```ruby:reviews_controller.rb
def search
  @tags = Review.tagged_with([params[:search_tag]]).order("created_at DESC").page(params[:page]).per(5)
end

#以下のactionを追記
def autocomplete
  all_tags = Review.tag_counts_on(:tags) #全てのタグを取得
  tags_name = all_tags.where('name LIKE(?)', "#{params[:term]}%").pluck(:name) #tagsテーブルのnameカラムを前方一致で取得
  render json: tags_name.to_json #前方一致で取得した値をjsonにする
end
```
acts-as-taggable-onをインストールすることで使える`tag_counts_on(:tags)`のメソッドを利用します。このメソッドを使うことで、DBに保存されているタグの値を全て取得することができます。

`pluck(:name)`の記述がない状態で、ローカル環境のlocalhost:3000/reviews/autocompleteにアクセスすると、今まで登録したタグが下の画像のように配列でズラリと並んでいる感じになります。
[![Image from Gyazo](https://i.gyazo.com/20902efb4162f184f063025a20bff652.png)](https://gyazo.com/20902efb4162f184f063025a20bff652)

このページに表示されている配列の値が、今後のサジェストにおけるソースになるわけですが、上の配列の状態のままだとサジェストがうまく機能しません。そのため、pluckメソッドを使ってnameカラムを指定し、nameの値だけを取得します。そうすると以下のような配列になります。
[![Image from Gyazo](https://i.gyazo.com/4d469098574c6d1cd60fd6846164aa60.png)](https://gyazo.com/4d469098574c6d1cd60fd6846164aa60)

##JavaScriptファイルを作成
assets配下のjavascriptフォルダにsearch.jsファイルを作成します。

```javascript:search.js
$(document).on('turbolinks:load', function(){
  $(".field").autocomplete({
    source: "/reviews/autocomplete", //サジェストで表示させる値の取得先
    autoFocus: true, //取得した値（サジェストの候補）に自動でフォーカスする
    minLength: 1 //1文字入力すればサジェスト機能が動くようにする
  })
});
```
`'turbolinks:load'`がないとサジェスト機能がうまく機能しなかった（一度リロードしないと機能しない）ため記述してみました。これで一応問題なく動きます。

## 適当な入力フォームを作成
あとは下のような入力フォームを作成してあげればいいだけです。

```ruby:search.html.haml
%h2
  タグで検索する
.search__form
  = form_with model: @review, url: search_reviews_path, method: 'get', local: true do |f|
    = f.search_field :search_tag, class: 'field', placeholder: "タグを入力してください"
    = f.submit 'Search', class: 'search-btn'
```
ポイントは`= f.search_field :search_tag, class: 'field'`の部分です。
先ほど作成したJavaScriptファイルでは、`field`というクラスが適用されたフォームで文字の入力があった際に発火するようにしたので、クラス名が違っていると動かないので要確認です。

以上で、簡易的なサジェスト機能の完成です。

# 終わりに
折角タグ機能を実装したのだから、ちゃんと生かせるようにしよう！と思い実装に着手したサジェスト機能でした。簡易的でしたが、思った以上に実装は簡単でした！今後は、より高度な実装に着手していきたいです。

# 参考記事一覧
[Rails | acts-as-taggable-on を使ったタグ機能の実装 | 備忘録](https://qiita.com/ddgg7755/items/e1caa8b73d118822a0a2)
[Railsのタグ機能の実装（gem：acts-as-taggable-on）]
(https://www.blograils.com/posts/rails-actsastag)
[railsでサジェスト機能を実装してみた]
(https://qiita.com/anuma/items/c76de8d009266491fba1)
[Rails】JQuery UI オートコンプリートを実装してみました【Javascript】]
(https://vastworld.org/code/925)