rails5でafter_commitが動かなくなってしまった

ITネタです。すいません。
railsのモデルデータに変更が加えられたらelasticsearchのデータをafter_commitで更新するようにしているのですが。

1
2
after_commit :index_elasticsearch_document, on: [:create, :update]
after_commit :delete_elasticsearch_document, on: [:destroy]

Rails5.1.4にしたら設定したcallbackが走らなくなってしまいました。
困っている人結構いるような気がするんですがどうなんでしょうかね。


onオプションをつけると動かなくて外すと動きます。
どうもcallbackが処理される過程のtransaction_include_any_action?によるどの操作(insert, update, destroy)での更新かとonオプションによる一致が正常に判定されず動かないようです。
ぐぐってみるとヒットするのはこのあたりでしょうか。

after_create_commit and after_update_commit alias don’t always run when next to each other #29554

after_commit doesn’t work with optimistic locking #29318

これのうち下のリンクが正解でした。
修正PRはこれですが、まだマージされてませんね。
このコミットが原因のようです。 5.0.2ではうごくみたいですw

ちなみに関わっている案件の場合は正確にはcomposite_primary_keysを使っているのでcomposite_primary_keysの方の悲観的ロックが原因でした。
メソッドオーバーライドしているのでほぼ同じ現象です。

ここPRと同じように@_trigger_update_callbackを設定すれば治ります。

ただパッチをあてるのもなって感じなのでモデル側でこうなおしました。

1
2
3
4
5
6
7
8
class ElasticsearchNoModel < ApplicationRecord
  def _update_record(*args)
    affected_rows = super
    if affected_rows == 1
      @_trigger_update_callback = true
    end
  end
end

create時とupdate時はこれで治りましたがdestroyの時がこれだとまだうごきません。
ちなみに今関わっている案件ではparanoia使ってます。

after_commit with on: option doesn’t work at Rails 5.1.3 #418

issueあがってますがリアクションありませんね。

ソース読んでこう直しました。

1
2
3
4
5
6
class ElasticsearchNoModel < ApplicationRecord
  def destroy
    @_trigger_destroy_callback = true
    super
  end
end

@_trigger_destroy_callbackをsuperの前に設定するのはparanoiaのメソッドがdeleted_atの更新とrun_callbackを同一メソッドでやっているためです(なるべくパッチorメソッドをいじりたくないので先に設定してしまっています)

これで無事にafter_commitが動くようになりました。

Comments