2
0

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 3 years have passed since last update.

[Rails6]RansackとGutentagを使ったタグの検索機能を実装する際につまずいたところ

Posted at

この記事について

タグ付け機能を実装したRailsのアプリケーションにタグ名の検索機能を実装しようとしたところ、つまずいた部分があったのでその解決策をまとめました。

環境

Rails6 (6.0.1)
ruby 2.7.0

参考

Rails6でブログのタグのacts-as-taggable-onがエラーになったので別のタグgem(gutentag tags)を使う
Ransack on Gutentag tags- undefined method `type' for nil:NilClass
https://github.com/pat/gutentag
https://qiita.com/ishidamakot/items/d50ed387fbd2e80f702d

Ransackとは

Railsで作成したアプリケーションに検索機能を実装するためのgemです。 Ransackを利用することで複数の条件を組み合わせた複雑な検索機能を簡単に実装することができます。 

Gutentagとは

Railsで作成したアプリケーションにタグ付け機能を実装するためのgemです。 Railsでタグ付け機能を実装する場合はacts-as-taggable-onというgemを使うので一般的ですが、こちらの記事にあるようにRails6では不具合が発生している模様で、今回はこちらのgemを利用しました。

つまずいたところ

私自身はRails5でacts-as-taggable-onとransackを組み合わせて検索機能を実装した経験があったので、同じようにでGutentagとRansackで検索機能を実装しようとしました。

具体的には、DBに保存されている記事のタイトル、記事の本文、記事のタグ名をOR検索するという処理内容。コードは以下。

Model

article.rb
def self.make_search_query(search_word)
  query = {}
  query[:combinator] = 'or'
  query[:groupings] = []
  search_word = '' if search_word.nil?
  search_word.split(/[  ]/).each_with_index do |word, i|
    query[:groupings][i] = { title_or_content_or_tags_name_cont_any: word }
  end
  Article.ransack(query)
end

Controller

articles_controller.rb
def search
  Article.make_search_query(@search_word).result(distinct: true)
end

これで検索処理を走らせたら
以下のエラーが発生してしまった。

NoMethodError: undefined method `type' for nil:NilClass

どうやらタグ名検索のところでエラーが発生している模様。

解決した方法

こちらのサイトに同じような問題に直面した人が質問しており、解決策も提示されていました。

どうやらGutentagをインストールすることで作成されるgutentag_tagsテーブルはransackの検索対象に含まれていないらしいです。そのため、検索対象に含めるようにconfig/initializersに設定ファイルを置かなければならないとのこと。

設定ファイルの内容は以下

config/initializers/gutentag.rb
if ActiveRecord::Base.connection.table_exists? 'gutentag_tags'
  model =  Object.const_get "Gutentag::Tag"
  model.singleton_class.class_eval do
    define_method(:ransackable_attributes) do |auth_object|
      auth_object = nil
      ['name']
    end
  end
end

このコードを自分なりに解釈すると

1.gutentag_tagsテーブルが存在するか確認する
2.存在する場合はObject.const_getで"Gutentag::Tag"クラスを取得する
3.singleton_class.class_evalによって特異クラスを定義する
4.ransackable_attributesメソッドを定義し、nameカラムを検索対象に指定。

という感じ。
これで、gutentag_tagsテーブルのnameカラムがRansackの検索対象になるようです。

とりあえず、再度Railsを再起動して検索処理を走らせると、無事にタグ名での検索も実行されました。

※ransackではransackable_attributesメソッドで検索対象とするカラムを指定することができます。

参考:https://qiita.com/ishidamakot/items/d50ed387fbd2e80f702d#検索できる項目の制限

まとめ

RansackとGutentagを使ってタグの検索機能を実装した際に、タグ名で検索されないというエラーが発生しましたが、gutentag_tagsテーブルのnameカラムをRansackの検索対象に指定することで解決することができました。gutentagに関する情報は少ないので、少しでもお役に立てれば幸いです。ただ、個人的にはObject.const_getやsingleton_class.class_evalなど100%は理解できていないので、もっと勉強が必要。

2
0
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
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?