gemを使ったタグ機能実装 備忘録
タグ機能をgemを使って実装してみました。
毎回自分自身調べて実装しているので、いい加減備忘録として記事にしてみました。
前半の内容は、すでに多くの人が記事にしている基本的なタグ機能の実装内容です。
後半は、タグによる絞り込み検索をやってみました。初心者の自分にとっては、結構苦戦しましたが、理解すれば意外とシンプルな構造になっています。
ちなみに下記のリンクを参考にして実装しています。
<参考リンク>
公式リファレンス:acts-as-taggable-on
Railsでacts-as-taggable-onを使ってタグ管理を行う - Rails Webook
開発環境
Rails バージョン5.2.2
ruby バージョン2.5.3
acts-as-taggable-on バージョン 6.0.0 → 今回使用したタグ機能のgem
bootstrap4
アプリケーション詳細
ベースは現場Railsのタスク管理アプリを使用しています。
acts-as-taggable-on について
-
タグ機能を実装できるgem
以前gemを使用せずにタグ機能を実装した時は、中間テーブルを作ったりと色々やりましたが、このgemを使うと一瞬でできます。 -
当たり前ですが、色んなメソッドが用意されている
find_related_skills
同じタグに関連するタスクが表示される
taggings_count
メソッドではないですが、該当のタグの使用回数が表示されている
tag_counts
全てのタグデータを取得できる
などなど.....他にもまだありました。
使い方等はリファレンスを参照してください。
- 同じ名前で登録したタグの場合は、同じIDになるようになっている
例:Rails
と別々のタスクで登録しても同じid
になる
実装内容
1. Gemfileに追加して、インストール
gem 'acts-as-taggable-on', '~> 6.0' #追加
$ bundle install
$ rails acts_as_taggable_on_engine:install:migrations
$ rails db:migrate
2. モデルとコントローラーに追加
対象のモデルとコントローラーに下記を追加する
class Task < ActiveRecord::Base
acts_as_taggable #追加
# acts_as_taggable_on :tags と同じ意味のエイリアス
# tags のなかにIDやら名前などが入る。イメージ的には親情報。
#略
end
class TasksController < ApplicationController
#略
private
def task_params
params.require(:user).permit(:name, :description, :tag_list)
#tag_list を追加
end
#略
end
3. 各ビューファイルの編集
まず、各Viewファイルを下記のように編集していく。
① タスク登録フォームにてタグを入力できるようにする
= form_with model: task, local:true do |f|
.form-group
= f.label :name
= f.text_field :name, class: 'form-control', id: 'task_name'
.form-group
= f.label :description
= f.text_area :description, rows: 5, class: 'form-control', id: 'task_description'
#タグ入力フォームを追加
.form-group
= f.label :tag_list
= f.text_field :tag_list, value: @task.tag_list.join(','), class: "form-control"
.form-group
= f.label :image
= f.file_field :image, class: 'form-control'
= f.submit nil, class: 'btn btn-primary'
② 入力されたタグが配列としてtag_list
に代入されていく。
@task.tag_list.join(',')
のおかけで,
で区切って複数のタグを入力できる
ここで、
rails, php, js, python
と入力した場合は、
tag_list = ["rails","php","js","python"]
という配列になる。
③ タスク一覧画面にタグを表示させる
- @tasks.each do |task|
tr id="task-#{task.id}"
td= link_to task.name, task_path(task)
td= task.created_at
#タグ表示欄を追加
td= render 'tasks/tag_list', tag_list: task.tag_list
td
= link_to '編集', edit_task_path(task), class: 'btn btn-primary mr-3'
= link_to '削除', task, method: :delete, remote: true, data: {confirm: "タスク「#{task.name}」を削除します。よろしいですか?"}, class: 'btn btn-danger delete', id: "delete_link_#{task.id}"
タスク詳細画面でも同じ表示の仕方をするのでrender
を利用してパーシャルファイルで処理してもらう。
パーシャルに流す前の処理としては、
task
には@tasksから取り出した一つのタスクデータが入っている。
tag_list
をメソッドとして使用すると、タスクに付いているタグが取り出せる。
tag_list
にtask.tag_list
で取り出したタグをパラメータとして渡してあげる。
④ 受け取ったパラメータを繰り返し処理し、一つ一つを分けて表示させる
- tag_list.each do |tag|
span.badge.badge-primary.mr-1.p-2= tag
この時、tag_list
に入っているタグをeach
で一つ一つ独立させている
ここまで実装すると、上記の画像のようにタグが表示されます。
もちろん編集も可能です。
ここまでが基本的なタグ機能の実装です。
4. タグの絞り込み機能の追加
タグをクリックすると同じタグが付いたタスクを絞り込めるように実装していきます。
gemを使わずにタグ機能を実装した時は、この絞り込み機能がめちゃくちゃ苦戦しました。
ただ、gemを使う場合は、逆に完成されているために何をどう変えたらいいのか、どう使ったらいいのかわからなかったので苦戦しましたが、、、
実装内容は以下の通りです。
やっていることは結構シンプルです。
先ほど実装したものを少しだけいじります。
① タグにリンクをつける
link_to
メソッドを使用してリンクにします。
このブロック内のtag
には一つだけのタグ名が入っている状況です。
- tag_list.each do |tag|
span.badge.badge-primary.mr-1.p-2
= link_to tag, tasks_path(tag_name: tag), class: "text-white"
② リンク先にパラメータを渡す
このtag
のタグ名をクリックした時の遷移先をタスク一覧画面にする。
その際、tag_name
にtag
のタグ名をパラメータとして渡してあげる。
例: ここでtag
にRails
というタグが入っていた場合は、Rails
というタグ名が一覧画面へパラメータとして渡される。
③ コントローラーで処理する
def index
#略
#タグ絞り込み
if params[:tag_name]
@tasks = Task.tagged_with("#{params[:tag_name]}")
end
end
tasksコントローラーのindexアクションにて処理します。
ここで便利なメソッドが登場。
tagged_with("タグ名")
で絞り込みができます。
(もちろん公式リファレンスにも載っています。)
なので、もしtag_name
に値が入っている場合は(タグをクリックされたら)
受け取ったtag_name
をtagged_with("タグ名")
のタグ名
に入れて絞り込みを実行してくれます。
処理が実行されると、同じtag_name
を持ったタスクが一覧で表示される仕組みです。
URLもhttp://localhost:3000/tasks?tag_name=Rails
とクリックしたタグ名で絞り込みができていることがわかります。
例: もしRails
というタグをクリックしたら
tag_name
はRails
という値を持って、indexアクションに渡されます。
そして、tagged_with("Rails")
という形になり、絞り込みが実行される
さいごに
gemは非常に便利ですが、少し変えようと思ったときに、何をしていいかわからなくなるのが現状でした。
ですが、リファレンスをしっかり読み、構造を少しでも理解すれば意外と頑張れるとうこともわかりました。
これからはリファレンスファーストを意識して取り組んでいければと思います。
読んでいただき、ありがとうございました。
備忘録として記事を書きましたが、もし間違っている内容等あればお気軽に編集リクエストをしていただければと思います。
以上です。