【Rails】 acts_as_taggable_onでハッシュタグ機能を作る

# 概要
タグ機能をさくっと作ることができるgem
acts_as_taggable_onを利用してハッシュタグ機能を作ります。

※２つの参考記事を組み合わせて多少手を加えただけです
https://qiita.com/d510/items/e1caa8b73d118822a0a2
https://qiita.com/MitsuTurtle/items/614b154641ab4e4b56ba

## 開発環境
Ruby 3.0.2
Rails 7.0.0
Bootstrap 5
slim

## 前提条件
既存のPostモデルがあるものとします。
Postのスキーマ情報
```ruby:schema.rb
create_table "posts", force: :cascade do |t|
    t.string "title"
    t.text "content"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
end
```

このPostモデルにハッシュタグ機能を追加します。

# acts_as_taggable_onの準備
Gemfileに追加してbundle install、マイグレーションします。
## acts_as_taggable_onをGemfileに追加
```ruby:Gemfile
gem 'acts-as-taggable-on' #追加
```
```
bundle install
```
## マイグレーション
```
rails acts_as_taggable_on_engine:install:migrations
```
```
rails db:migrate
```

## モデルとコントローラーを編集

```ruby:post.rb
class Post < ActiveRecord::Base
  acts_as_taggable #追加
end
```
```ruby:posts_controller.rb
class PostsController < ApplicationController

#（省略）
	
  private

  def post_params
    params.require(:post).permit(:title, :content, :tag_list) 
    #ストロングパラメーターにtag_listを追加
  end	
end
```

これでacts_as_taggable_onを使う準備は完了です。


# ハッシュタグ登録機能を追加
正規表現で半角「#」のついた文字列を探し、タグに追加します。
## モデルを編集
```ruby:post.rb
after_create do
   hashtags  = self.content.scan(/[#][\w\p{Han}ぁ-ヶｦ-ﾟー]+/)
   hashtags.uniq.map do |hashtag|
       tag = tag = hashtag.downcase.delete('#')
       tag_list << tag
   end
end

before_update do
   tag_list.clear
   hashtags = self.content.scan(/[#][\w\p{Han}ぁ-ヶｦ-ﾟー]+/)
   hashtags.uniq.map do |hashtag|
       tag = tag = hashtag.downcase.delete('#')
       tag_list << tag
   end
end
```

## タグをクリックで投稿を絞り込み
クエリパラメーター「tag_name」で投稿を絞り込めるようにします。

```ruby:posts_controller.rb
def index
    @posts = Post.all   
    @posts = Post.tagged_with(params[:tag_name]) if params[:tag_name]
end
```
ヘルパーを作成
```ruby:posts.helper.rb
module PostsHelper
    def render_with_hashtags(content)
        content.gsub(/[#][\w\p{Han}ぁ-ヶｦ-ﾟー]+/){|word| link_to word, posts_path(tag_name: word.delete("#"))}.html_safe
    end
end
```
一覧ページに表示させる
```ruby:views/posts/index.html.slim
    -@posts.each do |post|
        tr
            td = post.id
            td = post.title
            td = render_with_hashtags(post.content)
            td = link_to 'show', post_path(post), class: 'btn btn-primary'
            td = link_to 'edit', edit_post_path(post), class: 'btn btn-primary'
            td = link_to 'destroy', post_path(post), data: {turbo_method: 'delete', turbo_confirm: 'Are you sure?'}, class: 'btn btn-danger delete'
```

詳細ページに表示させる
```ruby:views/posts/show.html.slim
div.card
    div.card-header
        h4 =@post.title
    div.card-body
        p.card-text
           =simple_format(render_with_hashtags(@post.content))
```
詳細表示
![スクリーンショット 2023-01-22 13.08.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1480703/e438a6ec-3c54-0cd8-e0e3-9be94559bb0f.png)


タグの名前をクリックでタグがついた投稿を絞り込むことができます。
一覧表示
![スクリーンショット 2023-01-22 16.40.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1480703/935be298-4454-f913-126d-646298628b5e.png)


タグの名前をクリックした時のURL
`http://localhost:3000/posts?tag_name=ハッシュタグ1`


# 参考
https://qiita.com/d510/items/e1caa8b73d118822a0a2
https://qiita.com/MitsuTurtle/items/614b154641ab4e4b56ba
https://github.com/mbleigh/acts-as-taggable-on