Rails6にアップデートした時の問題
Rails6になってから、今まで使っていた acts-as-taggable-on
がエラーになるようになった。
原因は
まあ悪い意味での原因というわけではなく
この部分で set_attribute_was
が消されたため発生したもの
また、これの対応のブランチもあるのだが、初歩的なバグを含むため、ブランチ切り替えの対応してもあまり意味がない。
とはいえ、ライブラリへのPRも全然反映されないし、Gemfileが汚れるのも嫌なので別のやつを実験的に使ってみた。
というやつで、スターは315の、RubyGemダウンロード数は54,474というところなので、act-as-taggable-onのわずか6%程度のスター数となり、多少心もとない。
開発当初のブログがあるので、読んでみた
個人的には、act-as-taggable-onしか使ったことなかったので、とりあえず調べていたら、どうも2013年頃に開発されたようだ。
永続化周りをforwardableを使って委譲して実装してある
使ってみた
環境
- Rails 6.0.0
- ruby 2.6.3
Gemfile
記載したら、bundle install
する
gem 'gutentag', '~> 2.5'
インストール設定
ここは、よくあるお決まりのやつをただ打っていくだけ
migrateすることで、gutentagにより作られたマイグレーションファイルが実行され、使えるようになる
使う側のモデルにカラムを追加することなく使えるところが楽で良い
bundle exec rake gutentag:install:migrations
rails db:migrate
Schema例
create_table "blogs", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
Blog.rb
今回、ブログにタグ機能をもたせたいので、
ここにGutentag::ActiveRecord.call self
を置く
class Blog < ApplicationRecord
Gutentag::ActiveRecord.call self
include TagExtensions
end
FactoryBot.define do
factory :blog do
tags_as_string { "hoge,fuga,piyo" }
end
end
TagExtensions.rb
これは、いわゆるattr_accessor
の役割をinclude
して使うために別途作っただけ
メソッド毎モデルに直で書いても良いが、他のモデルでも使いたかったのでこのようにサクッと作っただけ。(若干気に入らないので後で修正する気がする)
module TagExtensions
def tags_as_string
tag_names.join(', ')
end
def tags_as_string=(string)
self.tag_names = string.split(/,\s*/)
end
end
作成時
View
一般的なinputタグに先程TagExtensionsで作ったgetterメソッドを配置しておく
.form
= f.label :tags_as_string
= f.text_field :tags_as_string, value: @blog.tags_as_string
Controller#create
Scaffoldして、必要なところだけ抜粋しておく
フォームから送られて新規作成するところの処理と、Strong Parametersの設置
class BlogsController < ApplicationController
def create
@blog = Blog.new(blog_params)
respond_to do |format|
if @blog.save
format.html { redirect_to blog_url(@blog), notice: 'Blog was successfully created.' }
format.json { render :show, status: :created, location: @blog }
else
format.html { render :new }
format.json { render json: @blog.errors, status: :unprocessable_entity }
end
end
end
def blog_params
params.require(:blog).permit(:tags_as_string)
end
end
一覧表示時
View
tag_namesなどで引っ張ってこれる
- @blogs.each do |blog|
- blog.tag_names.each do |tag|
= tag
Controller#index
例えばincludes
などをしないとN+1で死ぬので注意
class BlogsController < ApplicationController
def index
@blogs = Blog.includes(:tags)
end
end
挙動確認
実際にテストなどで挙動見てみるとこんなように使える
blog = Blog.create! # ブログ用レコード作る
blog.tag_names << 'hogehoge'
blog.tag_names #=> ['hoge']
blog.tag_names << 'fuga' << 'piyo'
blog.tag_names #=> ['hoge', 'fuga', 'piyo']
blog.tag_names -= ['fuga']
blog.tag_names #=> ['hoge', 'piyo']
blog.save # 保存する
感想
gutentag自体は、rails6にすぐ対応したcommitがあるし、issueのclose率も100%なのでけっこういいかなと思った。懸念点はpatという創造者しかほぼ保守していないところ。
acts-as-taggable-onは、使ってる人が多いので、また修正版が上がりそうなので、そのあたり様子見