行動すれば次の現実

ほどよくモダンなシステム開発を目指しています。メインテーマは生産性、Ruby、Javascriptです。

最低限知っておきたい!Railsのトランザクション実装例

Railsでトランザクションを使いたい方向けに実例を踏まえてわかりやすく解説をいたします。

RailsにおけるTransaction

Railsでトランザクションを使用する場合は、トランザクションの範囲をActiveRecord::Base.transactionブロックで囲む必要があります。

transactionブロック内で例外が発生した場合、ブロック内で行われたデータベース更新処理が全てロールバックされます。 Railsでtransactionを機能されるためには例外を発生させなければならないのです。

ActiveRecord::Base.transaction do
  user1.save!
  user2.save!
end

例外が発生すればロールバックされる

例外が発生すればロールバックされますので、例外を意識して実装する必要があります。

以下のサンプルコードをご覧ください。

def some_method
  # 省略...
  ActiveRecord::Base.transaction do # BEGIN
    user1.save!  # 実行される(ロールバックで戻る)
    raise 'error'  # ロールバック
    user2.save!  # 実行されない
  end
  foo # 実行されない
rescue => e
  bar # 実行される
end

raise 'error'により、user1.save!がロールバックされます。 user2.save!はそもそも実行されません。また、例外が発生した時点でfooも実行されないことになります。 rescueで拾っているbarは実行されます。

サンプルコードではsave!を使用していますが、saveメソッドを使用しても同様の結果になります。

ロールバック後に処理を継続したい場合

ロールバック後に処理を継続したいケースがあるかと思います。 例えばロールバック後に処理が失敗したことを特定のテーブルに書き出したいといったケースです。

その場合は、ロールバックする処理自体をメソッド化して例外を握りつぶせばロールバック後も処理を継続することが出来ます。

def do_transaction
  ActiveRecord::Base.transaction do
    user1.save!
    raise 'error'
  rescue StandardError
    false
  end
end

def fuga
  # 省略...
  if do_transaction
    # 成功時の処理
    foo
  else
    # ロールバック後の処理
    bar
  end
end