どうもこんにちは。
今回はRailsでDB操作をする時に便利なActiveRecord::Base.transaction
についてメモします。
トランザクションって何?
トランザクションをネットで検索すると、「ここからここまでワンセット」な処理単位が「トランザクション」 というわかりやすく説明してありました。
まさにその通りです。
この考えをDBの操作でも活用しているものがRailsにおけるトランザクションです。
使い方
基本的に、データの登録、更新、削除する時のメソッドとして使われます。
ActiveRecord::Base.transaction do ... end
ブロックでsaveメソッドやupdateメソッド処理の箇所を囲うようにして使用します。
def create
## データを登録するためのデータを作成
user = User.find(params[:id])
profile = Profile.new(user_id: user.id, hobby: '野球をすること', favorite_food: 'カレーライス')
post = Post.new(user_id: user.id, title: '自己紹介', content: '今日は野球の試合に行ってきました。')
## saveメソッドやupdateメソッドをtransactionブロックで囲う
ActiveRecord::Base.transaction do
user.save
profile.save
post.save
end
redirect_to posts_path
end
transactionブロックの中でエラーが発生しなければ何事もありませんが、どこかでエラーが起きたとします。
今回はPostモデルに以下のバリデーションが定義されているとして、インスタンスのtitleをnilとしましょう。
validates :title, presence: true
def create
## データを登録するためのデータを作成
user = User.find(params[:id])
profile = Profile.new(user_id: user.id, hobby: '野球をすること', favorite_food: 'カレーライス')
## エラーを発生させるためにtitleをnilとします
post = Post.new(user_id: user.id, title: nil, content: '今日は野球の試合に行ってきました。')
## saveメソッドやupdateメソッドをtransactionブロックで囲う
ActiveRecord::Base.transaction do
user.save
profile.save
post.save
end
redirect_to posts_path
end
そうすると、post.save
のところでエラーが発生するはずです。
transactionブロックで囲っていないと、userとprofileはデータベースに保存されるがpostが保存されないという状態になります。アプリケーションの要件によってはそれは良くない場合があります。
ただ、今回のコードではtransactionブロックで囲っているので、一度保存されたuserとprofileのデータはロールバックされ、どのデータも保存されていない状態になります。
これによってDBの整合性が保たれます。
transactionブロックを使用していると、開発も楽なのでおすすめです。
以上