🏷️
【Rails】gem:acts-as-taggable-on と Bootstrap Tags Input を使ったタグ機能① 実装編
gemを使ってタグ機能を実装します。
今回の記事ではタグの入力と表示までを実装します。
イメージ
-
タグ実装(posts.new)
簡単に1個ずつのタグが入力可能!
重複したタグは入力できないようになる!
消したいタグだけ消すことが可能! -
タグ表示(posts.show)
タグ付けされている件数が表示可能! -
タグ検索(tags.show)
環境
- ruby 3.1.2
- rails 6.1.7.4
- DB 開発環境:SQLite / 本番環境:MySQL
ER図
gemを入れてpostテーブルと繋げます。
流れ
- gem導入
- モデルとコントローラに追記
- コントローラ作成
- ビュー作成
- Bootstrap Tags Inputの導入
gem導入
- Gemifileに追記し、bundle install。
Gemifile
gem 'acts-as-taggable-on'
ターミナル
bundle install
- 以下を入力
ターミナル
rails acts_as_taggable_on_engine:install:migrations
入力するとファイルがいっぱい作成されます。
- マイグレーションファイルの修正
2つのマイグレーションファイルをコメントアウトして修正します。修正しないとSQLiteであれば使用できますが、MySQLへの本番環境のデプロイ時にエラーが発生します。(詳しくは以下の記事を参照ください)
以下のようになっていればOK。
- _add_missing_unique_indices.acts_as_taggable_on_engine
20230812064908_add_missing_unique_indices.acts_as_taggable_on_engine
# frozen_string_literal: true
# This migration comes from acts_as_taggable_on_engine (originally 2)
class AddMissingUniqueIndices < ActiveRecord::Migration[6.0]
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)
#remove_index ActsAsTaggableOn.taggings_table, name: 'taggings_taggable_context_idx'
#add_index ActsAsTaggableOn.taggings_table,
# %i[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, %i[taggable_id taggable_type context],
# name: 'taggings_taggable_context_idx'
end
end
- _add_missing_taggable_index.acts_as_taggable_on_engine
20230812064910_add_missing_taggable_index.acts_as_taggable_on_engine
# frozen_string_literal: true
# This migration comes from acts_as_taggable_on_engine (originally 4)
class AddMissingTaggableIndex < ActiveRecord::Migration[6.0]
def self.up
# add_index ActsAsTaggableOn.taggings_table, %i[taggable_id taggable_type context],
# name: 'taggings_taggable_context_idx'
end
def self.down
# remove_index ActsAsTaggableOn.taggings_table, name: 'taggings_taggable_context_idx'
end
end
- マイグレーションをする
ターミナル
rails db:migrate
モデルとコントローラに追記
モデル追記
使用したいモデルに以下を追記します。
post.rb
class Post < ApplicationRecord
# gem:acts_as_taggableの使用
acts_as_taggable_on :tags
:
上記により、Postモデルにタグ付けできるようになりました。
コントローラ追記
タグ表示のためのアクションと、コントローラのストロングパラメータにtag_list
を追記します。
俺の場合はshowとindexでタグを表示させます。
posts.controller.rb
class Public::PostsController < ApplicationController
:
def index
case params[:sort]
when 'favorites'
@posts = Post.sort_by_favorites.page(params[:page]).per(12)
when 'popular'
@posts = Post.sort_by_impressions_count.page(params[:page]).per(12)
else
@posts = Post.published.order(created_at: :desc).page(params[:page]).per(12)
end
@posts.each do |post|
impressionist(post, nil, unique: [:session_hash, :user_id])
end
end
def new
@post = Post.new
end
def show
@post = Post.find(params[:id])
+ @tags = @post.tag_counts_on(:tags)
end
private
def post_params
+ params.require(:post).permit(:title, :body, :link, :tag_list, :status)
end
解説:
上記で分かる通りindexアクションにはタグを追加していません。明示的に追加しなくとも、タグはindexや他のアクションでも問題なく表示されました。どうやら1つのアクションでタグ情報を取得すれば(今回はshow
で取得)、他のアクションで追加しなくもビューで表示できるようです(便利!)
今回は、そのタグの使用回数をカウントしたタグを表示たいため、tags_counts_on
を使っています。
メソッドは以下を参照ください。
メインメソッド | 説明 |
---|---|
tag_list |
特定のモデルのインスタンスに関連付けられたタグのリストを取得します。 |
tag_list.add("tag_name") |
特定のモデルのインスタンスに新しいタグを追加します。 |
tag_list.remove("tag_name") |
特定のモデルのインスタンスからタグを削除します。 |
tagged_with("tag_name") |
特定のタグ名に関連付けられたモデルのインスタンスを取得します。 |
tag_counts |
モデルに関連付けられたタグとその使用回数をカウントし、リストとして取得します。 |
most_used |
最も使用されているタグを取得します。 |
ビュー作成
タグ付けのフォーム
posts/new.html.erb
:
<%= form_with model: @post do |f| %>
:
<div class="form-group form-group_tags">
<%= f.label :tag_list, "Tag", class: "form-label" %>
<%= f.text_field :tag_list, value: @post.tag_list.join(","), class: "form-control", data: { role: "tagsinput" } %>
</div>
:
解説:
-
tag_list
:
テキストフィールドの名前としてtag_list
を指定します。 -
value: @post.tag_list.join(",")
:
join(",")とすることで、このタグリストをカンマで区切った文字列に変換し、初期値として表示します。これにより、投稿の編集時に既存のタグが正しく表示されます。joinしないと2つのタグを結合してしまいます。 -
data: { role: "tagsinput" }: tagsinput
]:
Bootstrap Tags Inputの導入。詳細は以下で説明します。
タグ表示画面
posts/show.html.erb
<div class="tags">
<% if @tags.present? %>
<div class="d-flex flex-wrap">
<% @tags.each do |tag| %>
<span class="badge badge-info mr-2 mb-2">
<%= link_to "#{tag.name}(#{tag.taggings_count})", tag_path(tag.name), class: "text-white" %>
</span>
<% end %>
</div>
<% else %>
<p>登録されているタグはありません</p>
<% end %>
</div>
このようにすると以下のように表示することができます。
Bootstrap Tgas Input導入
ライブラリのインストール
インストール方法はいくつかありますが、今回はyarnを使用しインストールします。
ターミナル
yarn add bootstrap-tagsinput
ライブラリのインポートとタグ入力フィールドの有効化
以下ファイルでインポートし、JavaScriptのコードも追加します。
これにより、タグ入力フィールドが有効になります。
app/javascript/packs/application.js
import 'bootstrap-tagsinput';
$(document).ready(function() {
$("input[data-role='tagsinput']").tagsinput();
});
htmlでタグ入力フィールドの作成
上述のタグ付フォームで記載済みです。
<%= f.text_field :tag_list, value: @post.tag_list.join(","), class: "form-control", data: { role: "tagsinput" } %>
-
data: { role: "tagsinput" }: tagsinput
]:
role属性に指定された値:tagsinputを使用して、JavaScriptの操作ができるようにします。
参考記事
以上で完成。
Discussion