概要
ActiveRecord Transactionであれば、処理途中で例外が発生した場合は
それまでのinsert、updateをロールバックしてくれると思っていましたが、
書き方によってはロールバックされないことがあるので、
ロールバックされる・されないパターンを整理してみました。
開発環境
- Ruby 2.6.5
- Rails 5.2.6
ActiveRecord::Base.transaction
ロールバックされない書き方
ActiveRecord::Base.transaction do
user = User.find_by!(name: 'テスト太郎')
# nameカラムを更新
user.update!(name: 'テスト太郎更新')
# Integer型のageカラムにStringを設定
user.update!(age: 'Invalid Value')
end
rescue StandardError => e
puts '例外エラーが発生しました。'
end
Integer型のageカラムに 文字列を入れてupdateしたことで例外が発生、
例外エラーが発生しました。
メッセージが出力されるが、
User nameのupdateはロールバックされず、 nameはテスト太郎更新
に更新される。
ロールバックされる書き方
begin
ActiveRecord::Base.transaction do
user = User.find_by!(name: 'テスト太郎')
# nameカラムを更新
user.update!(name: 'テスト太郎更新')
# Integer型のageカラムにStringを設定
user.update!(age: 'Invalid Value')
end
rescue StandardError => e
puts '例外エラーが発生しました。'
end
Integer型のageカラムに 文字列を入れてupdateしたことで例外が発生、
例外エラーが発生しました。
メッセージが出力される。
user nameのupdateはロールバックされ、 Userテーブル.nameカラムは更新されず、テスト太郎
のままになる。
感想
Railsを使い始めた頃、これにハマって
ロールバックのテストが通らず、何時間も無駄にしてしまったことがありましたが、
同じチームメンバーがこれにハマっていたのを見て
簡単に書いてみました。