elasticsearch-rails はElasticsearchとRails / ActiveRecordのインテグレーションをしてくれるgemです。
こいつを使っているとき、 特定条件下でモデル同士を比較するテストがコケるようになる という現象に悩まされてきました。pryなどで確認しても、たとえば
model_a
がes-railsからの返却値であるとき、 model_a == Model.find(model_a.id)
がコケるのです。これはクラスのリロードがうまくいっていないからではという示唆を得てSpringを切ると、たしかに再現しなくなりました。そこで elasticsearch-rails を調べたところ、 Elasticsearch::Model::Registry がモデルクラスのインスタンスを保持しているようでした。
Springのドキュメントにも触れているとおり、これはNGです。
https://github.com/rails/spring#class-reloading
Rails前提のgemがSpringに配慮したコードになっていないというのはバグといえるかどうか微妙なところですが、とにかく動かないのは困るのでモンキーパッチを当てて凌ぐことにしました。
Monkey Patch
module ElasticsearchMultipleRecordsExtension if defined?(::Spring) # Workaround for elasticsearch-rails's bug that Elasticsearch::Model::Registry keeps class instances but they are not reloaded on Spring ORIGINAL_TYPE_FOR_HIT = Elasticsearch::Model::Adapter::Multiple::Records.instance_method(:__type_for_hit) def __type_for_hit(hit) type = ORIGINAL_TYPE_FOR_HIT.bind(self).call(hit) Object.const_get(type.name) end end end Elasticsearch::Model::Adapter::Multiple::Records.prepend(ElasticsearchMultipleRecordsExtension)
elasticsearch-rails にもpull-requestを送ろうと思ったのですが、bundle installがコケるレベルでメンテされてないので一旦諦め。