概要
Railsでgem acts-as-taggable-onを使って、タグ機能を付けました。
私が付けた機能は、新規投稿から、既存のタグ(seedファイルに)を用意しておいて、そこから複数選べるタグ機能です。
下記イメージです。
環境
Ruby 2.5.7
Rails 5.2.4.2
デザインBootstrap使用
実装
① インストール
gem 'acts-as-taggable-on', '~> 6.0'
$ bundle install
② テーブル作成
$ rails acts_as_taggable_on_engine:install:migrations
$ rails db:migrate
③ モデルとコントローラーに追記
class Style < ApplicationRecord
acts_as_taggable #追加
end
indexには、タグ一覧とタグを押したときにタグ付けしてあるものを表示。
def index
@tags = ActsAsTaggableOn::Tag.all
# タグの一覧表示
if params[:tag]
@styles = Style.tagged_with(params[:tag])
# タグ検索時にそのタグずけしているものを表示
else
@styles = Style.all
end
def new
@style = Style.new
@tags = ActsAsTaggableOn::Tag.all
end
def show
@style = Style.find(params[:id])
end
def create
@style = Style.new(style_params)
@style.user_id = current_user.id
if @style.save
flash[:notice] = "スタイルを登録しました"
redirect_to style_path(@style.id)
else
@tags = ActsAsTaggableOn::Tag.all
render :new
end
end
# update・destroyは同じような形なので省略します
private
def style_params
params.require(:style).permit(:name, :user_id, :image, tag_list: [])
# tag_list: [] を追記
end
end
④ seedファイルに追記
今回は、既存のタグを用意するので、seedファイルを活用。
# タグ付紐付け(%w()の中に記述)
array = %w(キュート ナチュラル エレガント モード レディースマッシュ メンズマッシュ ショートボブ 内巻きボブ ショートレイヤー ロングレイヤー レイヤー レディース刈上げ メンズ刈上げ メンズカット メンズツーブロック レディースツーブロック モヒカン メンズビジネス 女の子 男の子 学生 ミセス バレイヤージュ メッシュ グラデーションカラー 芸能人 編み込み 結婚式 成人式 卒業式 和装 パーティー カジュアル メイクキュート メイクモード メイクナチュラル メイクエレガント メイク成人式 メンズウルフ レディースウルフ グラデーションボブ 外ハネボブ 前下がり スポーティー グレイヘア インナーカラー イヤリングカラー メンズパーマ レディースパーマ メンズメッシュ メンズカラー)
array.each{ |tag|
tag_list = ActsAsTaggableOn::Tag.new
tag_list.name = tag
tag_list.save
}
$ rails db:seed
⑤ viewに記述
- index.html.erb
<div class="col-xs-12">
<% @tags.each do |tag| %>
<%= link_to "#{tag.name}(#{tag.taggings_count})", tag_path(tag.name), class: "label label-default" %>
<% end %>
</div>
- new.html.erb
<%= form_for @style do |f| %>
<div class="col-xs-12">
・・・・・・・
<label class="col-sm-12">タグ</label>
<div class="col-sm-12">
<% @tags.each do |tag| %>
<%= f.check_box :tag_list, { multiple: true }, "#{tag.name}", nil %>
<%= f.label " #{tag.name}(#{tag.taggings_count})", class: "label label-default" %>
<% end %>
</div>
<div class="col-sm-12 text-right">
<%= f.submit "新規作成", class: "btn btn-danger" %>
</div>
</div>
</div>
<% end %>
- show.html.erb
<label class="col-sm-12 my-top">
<%= raw(@style.tag_list.map { |t| link_to t, tag_path(t), class: "label label-default" }.join(' ')) %>
</label>
以上で下記のような感じになります。
- new.html.erb
- index.html.erb
indexのtagged_with(params[:tag])では、タグの絞り込みを行っています。タグをクリックするとタグに紐でくデータが表示されます。
#{tag.name}では、タグ名の表示。#{tag.taggings_count}は、タグの登録数が表示されます。
以上で、実装完了です。
補足
本番環境にデプロイ時、acts-as-taggable-onでエラーが出てしまいました。エラーが出た方は、参考にしてもらえればと思います。
タグテーブルの修正が必要なのですが、
t.references :tag, foreign_key: { to_table: ActsAsTaggableOn.tags_table }
上記の外部キーを設定しているにも関わらず、
remove_index ActsAsTaggableOn.taggings_table, :tag_id if index_exists?(ActsAsTaggableOn.taggings_table, :tag_id)
外部キーを削除せずにインデックスを削除しようとしているからみたいです。
なので下記のような形にすると動きました。
# This migration comes from acts_as_taggable_on_engine (originally 2)
if ActiveRecord.gem_version >= Gem::Version.new('5.0')
class AddMissingUniqueIndices < ActiveRecord::Migration[4.2]; end
else
class AddMissingUniqueIndices < ActiveRecord::Migration; end
end
AddMissingUniqueIndices.class_eval do
def self.up
add_index ActsAsTaggableOn.tags_table, :name, unique: true
# 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
remove_index ActsAsTaggableOn.taggings_table, name: 'taggings_taggable_context_idx'
add_index ActsAsTaggableOn.taggings_table,
[:tag_id, :taggable_id, :taggable_type, :context, :tagger_id, :tagger_type],
unique: true, name: 'taggings_idx'
end
def self.down
remove_index ActsAsTaggableOn.tags_table, :name
remove_index ActsAsTaggableOn.taggings_table, name: 'taggings_idx'
add_index ActsAsTaggableOn.taggings_table, :tag_id unless index_exists?(ActsAsTaggableOn.taggings_table, :tag_id)
add_index ActsAsTaggableOn.taggings_table, [:taggable_id, :taggable_type, :context], name: 'taggings_taggable_context_idx'
end
end
こちらは、下記を参考にさせてもらいました。
https://teratail.com/questions/224720
開発環境では、問題なかったところでエラーがgemで出たので、焦りました、、、
参考になれば幸いです。