Edited at

ActiveRecord::Base.transactionで囲うタイミング

More than 3 years have passed since last update.

分けることができない処理

ActiveRecord::Base.transaction do

end

で囲うのはもちろんとして、

Railsは

ActiveRecord::Base.transaction do

end

で囲っていなくても、DBをコミットしたりロールバックする処理が自動で走るのだが、

後から見て自動で走るポイントがわかりずらいので、明示的に

ActiveRecord::Base.transaction do

end

で囲ったほうがよいかも。

なので、下記のような形にすることがあるかな。

def hoge

ActiveRecord::Base.transaction do
foo.save!
end

ActiveRecord::Base.transaction do
bar.save!
end
rescue ActiveRecord::RecordInvalid
# エラーハンドリング
end

でも、本当は、明示的に囲うのではなく、分けてもよい処理なら

def hoge

unless foo.save
# エラーハンドリング
return
end

unless bar.save
# エラーハンドリング
return
end
end

もありかな。 上記は別のオブジェクトへのsaveが2回以上でてくる例なので、

トランザクションで囲ってrescue ActiveRecord::RecordInvalidでエラーハンドリングするのか、

unlessでエラーハンドリングするのか悩みどころだが、saveが1個のみなら、

def hoge

unless foo.save
# エラーハンドリング
return
end
end

unless形1択で、

def hoge

ActiveRecord::Base.transaction do
foo.save!
end
rescue ActiveRecord::RecordInvalid
# エラーハンドリング
end

とはしないのが普通かな?

eachとかで何回も保存するときは、要件的に分けられない処理と考えられることが多いので、

def hoge

ActiveRecord::Base.transaction do
foos.each do|foo|
foo.save!
end
end
rescue ActiveRecord::RecordInvalid
# エラーハンドリング
end

の形になることが多い気がする。

んー、後からみて自動で走るポイントがわかりずらいと、始めに書いたが、

おそらく、savesave!を何も考えずに書けば、都度コミットが走って、save!のときはロールバックも走るのだと推測している。