Posted at

searchkickで多対多のデータを同期的にインデックスさせる

More than 3 years have passed since last update.

ElasticseachをRubyから扱えるようになるsearchkickというgemがある。

このgemには、例えばUserというモデルにデータが追加されるとそれと同時にElasticsearch側にそのインデックスを作ってくれる便利機能がある。

また、Userを親に持つAddressという子モデルがある場合も以下のように書くとUserに紐づくAddressが新規に追加されたとき同時にインデックスを作成してくれる。

class Address < ActiveRecord::Base

belongs_to :user

after_commit :reindex_user

def reindex_user
user.reindex
end
end

1対1や多対1のような関連の時にはこのやり方でいいのだけど、多対多のときは少し工夫が必要になる。

例えば、

(親)Article

(中間)ArticleTagging

(親)Tag

のような多対多の構成の関連があったとき、Articleに紐づくTagが追加されたときにそのTagをインデックスしたいとする。

公式のやり方に則ると下記のようになるけれども、

class Tag < ActiveRecord::Base

has_many :article_taggings
has_many :articles, through: :article_taggings

after_commit :reindex_article

def reindex_article
article.reindex
end
end

これだとうまくいかない。

多対多でもうまく同期的にインデックスさせるためには、下記のように中間モデルに記述する。

class ArticleTagging < ActiveRecord::Base

belongs_to :tag
belongs_to :article
after_commit :reindex # after_saveだとFactoryGirlを使っているときにコケる

def reindex
article.reload.reindex
end
end

これでうまくいく。

【参考】