【Rails】ハッシュタグ風タグ機能②

こんにちは！
この記事では、 **「[ハッシュタグ風タグ機能①](https://qiita.com/kizakey18/items/987edb870d449bb89405)」** の続編で追加機能やデザインを実装していきます！
具体的には、
[1. タグ一覧ページの追加](#1-タグ一覧表示ページの作成)
[2. タグのデザイン変更](#2-タグのデザイン変更)
[3. タグ検索の導入](#3-タグ検索の導入)
[4. チェックボックスによるタグ検索](#4-チェックボックスによるタグ検索)
[5. タグの数ランキング](#5-タグの数ランキング)
を実装していきます！お好みで追加してください！

### 完成イメージ
![スクリーンショット 2022-08-10 18.40.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/820462/3e401e07-b2e2-2fa3-acaa-2853aaa47880.png)

# 開発環境
Ruby on Rails 6

# 前提
[ハッシュタグ風タグ機能①](https://qiita.com/kizakey18/items/987edb870d449bb89405)の記事が実装済みであること。

# 実装
# 1 タグ一覧表示ページの作成
### 1-1. routingの追加
```ruby:app/config/routes.rb
Rails.application.routes.draw do
  root 'posts#index'
# ===========追記================
  get 'posts/top' => 'posts#top'
# ==============================
  devise_for :users
  resources :posts  
  resources :users
  resources :tags do
    get 'posts', to: 'posts#search'
  end
end
```
今回は`top`というページを作成することにしました。（この命名はなんでもいいです）

### 1-2. controllerに定義
```ruby:app/controllers/posts_controller.rb
class PostsController < ApplicationController
   #省略
# ===========追記================
  def top
   @tag_list = Tag.all
  end
# ==============================

  private

  def post_params
    params.require(:post).permit(:body, :content)
  end
end
```

### 1-3. viewの追加
実際にタグを表示させるビューを作成していきます。これは
[ハッシュタグ風タグ機能①](https://qiita.com/kizakey18/items/987edb870d449bb89405)の7-2と同様の手順なため詳細は省きます。
```app/views/posts/top.html.erb
<h3>タグ一覧</h3>
<% @tag_list.each do |list| %>
  <div class = 'tag一覧' >
    <%= link_to list.tag_name, tag_posts_path(tag_id: list.id) %>
    <%= "(#{list.posts.count})" %>
  </div>
<% end %>
```

これで一通り完成し、タグリストだけ一覧で表示することができるようになりました！

# 2 タグのデザイン変更
[ハッシュタグ風タグ機能①](https://qiita.com/kizakey18/items/987edb870d449bb89405)ではタグを **#** で表してましたが、**[FontAwesome](https://fontawesome.com/)** を導入しタグのデザインを以下のように変更していこうと思います！
![スクリーンショット 2022-08-10 19.02.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/820462/ba9c243b-458a-f19b-9118-5ac0c9fe10c0.png)
とっても簡単に実装できます！

### 2-2. FontAwesomeを導入
FontAwesomeを使う事前準備として、application.html.erbに一行追加します。
```app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>Geektwitter</title>
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
# 追記箇所
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.14.0/css/all.css">
#ここまで
    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>
```
下のリンクに詳しい解説が載っています。
[FontAwesomeの使い方](https://qiita.com/Onoshunn/private/381ea7ab6296c32e3947)

### 2-2. FontAwesomeを適応
FontAwesome導入後のViewが以下です！
```app/views/posts/top.html.erb
<h3>タグ一覧</h3>
<% @tag_list.each do |list| %>
  <div class = 'tag一覧' >
    ↓変更箇所
    <i class="fas fa-tag"><%= link_to list.tag_name, tag_posts_path(tag_id: list.id) %></i>
    ↑変更箇所
    <%= "(#{list.posts.count})" %>
  </div>
<% end %>
```

アイコンはとてもたくさん種類があるので、今回選択してるフォント以外でも自由に選んで使ってください！
これでフォントに関しては終わりです！

# 3 タグ検索の導入
次に、タグ一覧ページにて、タグの検索を行えるように実装していきます！

### 3-1. controllerの編集
```ruby:app/controllers/posts_controller.rb
class PostsController < ApplicationController
  #省略
  def top
    # ↓変更箇所
    if params[:search] != nil && params[:search] != ''
      search = params[:search]
      @tag_list = Tag.where("tag_name LIKE ?", "%#{search}%")
    else
      @tag_list = Tag.all
    end   
    # ↑変更箇所
  end

  private

  def post_params
    params.require(:post).permit(:body, :content)
  end
end
```
これは通常の検索機能と変わらないので、解説は割愛します。

### 3-2. viewの変更
```app/views/posts/top.html.erb
<h3>タグを検索</h3>
<%= form_tag({controller:"posts",action:"top"}, method: :get) do %>
    <%= text_field_tag :search %>
    <%= submit_tag '検索する'  %>
<% end %>
<br>

#　省略
```
これでタグ検索機能が実装できました！難しくなかったですよね！

# 4 チェックボックスによるタグ検索
3章ではタグ検索を実装しましたが、チェックボックスでのタグ検索を実装していきます。
これは記述式の検索とどちらがいいか、ご自身のwebサイトと相談して決めてください。（もちろん併用もありです）

今回は、投稿一覧ページであるindexに実装しています。
### 4-1. controllerの編集
```ruby:app/controllers/posts_controller.rb
class PostsController < ApplicationController
  #省略
  def index
    @tag_list = Tag.all.sort {|a,b| b.posts.count <=> a.posts.count} 
    if params[:search] != nil && params[:search] != ''
      search = params[:search]
      @posts = Post.joins(:tags).where("body LIKE ? OR tag_name LIKE ?", "%#{search}%", "%#{search}%")
    else
      @posts = Post.all
    end
# ===========追記================
    # チェックボックスによるタグ検索
    if params[:tag_id]
      @posts = []
      params[:tag_id].each do |key, value|      
        @posts += Tag.find_by(tag_name: key).posts if value == "1"
      end
      @posts.uniq!
    end
# ==============================
  end

  private

  def post_params
    params.require(:post).permit(:body, :content)
  end
end
```
### 4-2. viewの変更
```app/views/posts/index.html.erb
#　省略

<h3>タグ検索のチェックボックス</h3>
<%= form_tag({controller:"posts",action:"index"}, method: :get) do %>
  <% Tag.all.each do |t| %>
    <div class = 'check_box'> 
      <%= check_box :tag_id, t.tag_name %><%= t.tag_name %><%= "(#{t.posts.count})" %>
    </div>
  <% end %>
  <%= submit_tag '検索' %>
<% end %>

#　省略
```
以上になります！チェックボックスで検索するのもありですよね！


# 5 タグの数ランキング
今回、ランキングを導入するのは、以下のような意図があります。任意ですので、ご自身で判断してください。

> [ハッシュタグ風タグ機能①](https://qiita.com/kizakey18/items/987edb870d449bb89405)では、Tagを編集・削除しても、DBからTagの情報が消されず、タグの数が**0**と表示されてしまうため、ランキング化することにより、一番下にタグ数**0**のタグを表示させて、デザイン的に綺麗にしてます。
Tagの削除機能が実装できれば、この問題は解決できるので、わかる方いらっしゃればご教授いただけると嬉しいです。。。

とはいえ、ランキング化はとっても簡単で、1行で終わるので、パパッと実装してしまいましょう！

controllerを編集するだけです！
```ruby:app/controllers/posts_controller.rb
class PostsController < ApplicationController
  #省略
  def top
    if params[:search] != nil && params[:search] != ''
      search = params[:search]
      @tag_list = Tag.where("tag_name LIKE ?", "%#{search}%")
    else
      # ↓変更箇所
      @tag_list = Tag.all.sort {|a,b| b.posts.count <=> a.posts.count} 
      # ↑変更箇所
    end   
  end

end
```
```ruby
@tag_list = Tag.all.sort {|a,b| b.posts.count <=> a.posts.count} 
```
ここでは`sort`というrubyのメソッドを使って順序を操作して、tagの投稿数順に並び替えてます！
簡単ですね！

以上で終わります！
長々とお付き合いいただきありがとうございました〜