気になったこと
ActiveRecordのhookはかなり便利で、レコードのCRUDに合わせてさまざまな処理を入れることができます。
hookした処理内でエラーが発生した時のレコード操作はrollbackされるのかちょっと気になったので確認しました。
結論
after_create
=> hook内でエラーが発生した時にはレコード操作がrollbackされる
after_create_commit
=> hook内でエラーが発生してもレコード操作はcommitされている(それはそうですよね)
前提
ActiveRecordをテストするので何もないテーブルを作成。
create_table :tests do |t|
t.string :hoge
end
after_create
class Test < ActiveRecord::Base
after_create :raise_error
def raise_error
raise 'after create error'
end
end
Test.create!
after_createでraiseしつつレコードを作成してみます
実行結果
[1] pry(main)> class Test < ActiveRecord::Base
[1] pry(main)* after_create :raise_error
[1] pry(main)*
[1] pry(main)* def raise_error
[1] pry(main)* raise 'after create error'
[1] pry(main)* end
[1] pry(main)* end
:raise_error
[2] pry(main)> Test.create!
(7.9ms) SET NAMES utf8mb4 COLLATE utf8mb4_bin, @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'), @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
(0.6ms) BEGIN
Test Create (0.7ms) INSERT INTO `tests` VALUES ()
(2.0ms) ROLLBACK
RuntimeError: after create error
from (pry):5:in `raise_error'
transaction内でROLLBACKが発生しているのがわかります。
after_create_commit
class Test < ActiveRecord::Base
after_create_commit :raise_error
def raise_error
raise 'after create commit error'
end
end
Test.create!
実行ログ
[1] pry(main)> class Test < ActiveRecord::Base
[1] pry(main)* after_create_commit :raise_error
[1] pry(main)*
[1] pry(main)* def raise_error
[1] pry(main)* raise 'after create commit error'
[1] pry(main)* end
[1] pry(main)* end
:raise_error
[2] pry(main)> Test.create!
(17.7ms) SET NAMES utf8mb4 COLLATE utf8mb4_bin, @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'), @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
(0.8ms) BEGIN
Test Create (0.4ms) INSERT INTO `tests` VALUES ()
(2.9ms) COMMIT
RuntimeError: after create commit error
from (pry):5:in `raise_error'
SQLのCOMMITが入った後にエラーがraiseされているのがわかります。