CubicLouve

Spring_MTの技術ブログ

ActiveRecordのcallbackの実装を調べたときのメモ

Railsのcallbackの実体

callbackはActiveSupport::Callbacksを使って定義されます。

github.com

ActiveRecordのcallback

ActiveRecord::Callbacksに定義があります。

github.com

ここでcreateなどが定義されます。

github.com

define_model_callbacksは下記で実装されています。

github.com

例 : after_create hookの呼び出され方

ActiveRecord::Baseを継承したUserクラスを考えます。

Railsのバージョンは6.1.4.6を使っています。

Userクラスにはcreateというクラスメソッドがあり、recordを登録できます。

実体は、

irb(main):002:0> User.method(:create)
=> #<Method: User(id: integer, .....).create(attributes=..., &block) /path/to/..../gems/activerecord-6.1.4.6/lib/active_record/persistence.rb:33>

なので、下記です。

github.com

hookがどのように呼び出されるかがわかりにくいので、下記でbreak pointを仕込んでおきます。

github.com

で、after_commit のcallbackをなにかしら設定しておいて、User.createを実行してみます

irb(main):001:0> User.create(....)

[1] pry(User)> 

  TRANSACTION (0.2ms)  BEGIN

From:  /path/to/..../gems/activerecord-6.1.4.6/lib/active_record/callbacks.rb:461 ActiveRecord::Callbacks#_create_record:

    460: def _create_record
 => 461:   binding.pry
    462:   _run_create_callbacks { super }
    463: end

とまりましたね。 ここでcallerを一部抜粋すると

 "/activerecord-6.1.4.6/lib/active_record/callbacks.rb:461:in `_create_record'",
 "/activerecord-6.1.4.6/lib/active_record/timestamp.rb:108:in `_create_record'",
 "/activerecord-6.1.4.6/lib/active_record/persistence.rb:903:in `create_or_update'",
 "/activerecord-6.1.4.6/lib/active_record/callbacks.rb:457:in `block in create_or_update'",

"/activerecord-6.1.4.6/lib/active_record/persistence.rb:477:in `save'"

saveから callbacksの _create_record が呼ばれて、ここでcallbackが発動することとなります。

after_createはcommit前に発動するので、このcallback内で新しくinsertした内容を別のトランザクションからは取得できないので要注意です。