👋

ActiveRecord のコールバックを明示的に呼び出す

に公開

ActiveRecord のコールバックを明示的に呼び出したかたので覚書。
次のように #run_callbacks に呼び出したいイベントを渡すことで任意のコールバックを明示的に発火することができます。

class User < ActiveRecord::Base
  before_create -> { puts "before create" }
  after_create -> { puts "after create" }

  before_save -> { puts "before save" }
  after_save -> { puts "after save" }
end

user = User.new
user.run_callbacks(:create)
puts
user.run_callbacks(:save)
__END__
output:
before create
after create

before save
after save

こんな感じで createsave のコールバックを呼び出すことができます。

#run_callbacks にブロックを渡したときの挙動

#run_callbacks にブロックを渡した場合 beforeafter 間でそのブロックが呼び出されます。

class User < ActiveRecord::Base
  before_save -> { puts "before save" }
  after_save -> { puts "after save" }
end

user = User.new
user.run_callbacks(:save) { puts "saving" }
__END__
output:
before save
saving
after save

このときに注意する必要があるのは『ブロックの戻り値が false の場合はその後の処理は中断され after_xxx は呼びされない』という点です。

class User < ActiveRecord::Base
  before_save -> { puts "before save" }
  after_save -> { puts "after save" }
end

user = User.new
# false を返すと after_save は呼ばれない
user.run_callbacks(:save) { false }
__END__
output:
before save

また nil を返した場合は中断されずに after_save が呼び出されます。

class User < ActiveRecord::Base
  before_save -> { puts "before save" }
  after_save -> { puts "after save" }
end

user = User.new
# nil を返すと after_save は呼ばれる
user.run_callbacks(:save) { nil }
__END__
output:
before save
after save

いわゆる かどうかで判定してるわけではなくて false の場合は、で判定しているみたいですね。

関連

GitHubで編集を提案

Discussion