0
1

More than 3 years have passed since last update.

acts-as-taggable-onを使用したタグ付け機能

Posted at

acts-as-taggable-onを使用したタグ付け機能

・ここでは、gem 'acts-as-taggable-on'を使ったタグ機能の実装について書かせていただきますの、どうぞよろしくお願いします。

・僕自身が上記のgemを使ってエラーが頻繁に出たので、それらを解決したい方に是非読んでいただきたいと思います。
※また、こちらの記事の修正点がある場合はコメントして頂けると幸いです。

開発環境

Rails 6.0.3.2
ruby 2.6.5
acts-as-taggable-on バージョン 6.0.0
データベース mySQL

実装内容

1, gemを追加してインストール

Gemfile
gem 'acts-as-taggable-on', '~> 6.0' #追加
$ bundle install

2, マイグレーションファイルをインストール

$ rails acts_as_taggable_on_engine:install:migrations

成功するとマイグレーションファイルが生成される。

あとで記載する

3, マイグレーションを実行

$ rails db:migrate
Mysql2::Error: Cannot drop index 'index_taggings_on_tag_id': needed in a foreign key constraint: DROP INDEX `index_taggings_on_tag_id` ON `taggings`
~
ActiveRecord::StatementInvalid: Mysql2::Error: Cannot drop index 'index_taggings_on_tag_id': needed in a foreign key constraint: DROP INDEX `index_taggings_on_tag_id` ON `taggings`
~
Mysql2::Error: Cannot drop index 'index_taggings_on_tag_id': needed in a foreign key constraint

しかし、ここでエラーが発生。
※筆者は、ここで原因が分からず数日悩みました。

調べて見るとDBを「mySQL」にしている場合は初期導入で色々問題があるようなのでmigrateを実行する前にrails acts_as_taggable_on_engine:tag_names:collate_binを実行する必要があります。
※tagsテーブルのnameカラムは'binary encoded string'(パソコンで扱う2真数の文字列)として読み込まれるので、'utf8_bin'で読まなければいけないらしいです。

$ rails acts_as_taggable_on_engine:tag_names:collate_bin #実行

また、gemのバグで、
acts_as_taggable_on_migration.acts_as_taggable_on_engine.rbのマイグレーションファイルの15行目で外部キーを設定しているにも関わらず、

acts_as_taggable_on_migration.acts_as_taggable_on_engine.rb
t.references :tag, foreign_key: { to_table: ActsAsTaggableOn.tags_table }

add_missing_unique_indices.acts_as_taggable_on_engine.rbの11行目で外部キーを削除せずにインデックスを削除しようとしているためエラーが出ます。

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)

ここで、GitHubのissuesから不具合報告の内容を確認
※上記の1文は削除し、下記4文を追加してください

add_missing_unique_indices.acts_as_taggable_on_engine.rb
(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) #削除
if index_exists?(ActsAsTaggableOn.taggings_table, :tag_id) #追加
  remove_foreign_key :taggings, :tags                      #追加
  remove_index ActsAsTaggableOn.taggings_table, :tag_id    #追加
end                                                        #追加

Fix: マイグレーションがエラーになる不具合を修正

・これでマイグレーションファイルが導入できます!
 バグ解消前にrails db:migrateを実行した場合は、ArgumentErrorが出ます。
 一度目のmigrate実行時に最初のファイルだけ読み込んでるからですね!
 その場合はrails db: rollbackでmigrateを実行する前の状態に戻しましょう。

※こういった、gemのバグは今後も考えて検索しないといけなくなりますね。。。

4, モデルとコントローラーに記述を追加

・タグ付けしたい記事等のモデルとコントローラーを作成後、ファイルに下記のような内容で記述しましょう。
※今回は、postとしてモデルとコントローラーを作成しています。

post.rb
class Post < ApplicationRecord
  acts_as_taggable  #追加(acts-as-taggable-onの別名)
~
end
posts_controller.rb
class PostsController < ApplicationController

  def index
    @post = Post.includes(:user,:tags).all.order('created_at DESC')
  end

  def new
    @post = Post.new
  end

  def create
    @post = Post.new(post_params)

    if @post.save
      flash[:notice] = "投稿が保存できました"
      redirect_to root_path
    else    
      @post = Post.new
      flash.now[:alert] = "投稿できません、もう一度入力してください"
      render :new
    end

#略

private
  def set_post
    @post = Post.find(params[:id])
  end

  def post_params
    #tag_listをpermitに追加
    params.require(:post).permit(:title, :text, :tag_list).merge(user_id: current_user.id)
  end

end

5, ビューファイル編集(保存ページ)

new.html.haml
 # 略
= form_with(model: @post, local: true) do |f|
 # 略
  .form-contents__tag
    = f.label :tag_list
    = f.text_field :tag_list, value: @post.tag_list.join(","), autocomplete: "tag", class: "tag-field", placeholder:'タグを入力してください'

これでDBに値が保存されます!
tagsテーブルの[name]カラムに入力したタグと同じ名前があればレコードは増えずに、[taggings_count]のカウントが増えていきます。

6, ビューファイル編集(一覧表示)

続いてDBに保存されたタグを表示させます。

posts_controller.rb
  def index
    @post = Post.includes(:user,:tags).all.order('created_at DESC')
    if params[:tag_name]
      @posts = Post.tagged_with("#{params[:tag_name]}")
    end
  end

indexアクションにて一覧表示させます。
N+1問題を考慮してincludes(:tags)を記述しましょう。

index.html.haml
- @post.each do |post|
  %ul.posts__left__group__post-tag

最後に

長くなりましたが、acts-as-taggable-onを使用したタグ付け機能はここまでで実装ができます。

実装時には、3,マイグレーション実行の際には、ぜひお気をつけてください。

acts-as-taggable-onは他にもタグの使用頻度で検索を掛けれたりと便利なメソッドがあるので、一度リファレンスを見ていただけると良いかなと思います!
GitHub acts-as-taggable-on

以下、導入編同様に参考にさせていただいた記事になります。
Rails | acts-as-taggable-on を使ったタグ機能の実装 | 備忘録

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1