9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Rails6でブログのタグのacts-as-taggable-onがエラーになったので別のタグgem(gutentag tags)を使う

Posted at

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は、使ってる人が多いので、また修正版が上がりそうなので、そのあたり様子見

9
3
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
9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?