トランザクション中の例外について
トランザクションを使いたい時は、ActiveRecord::Base.transactionメソッドにブロックを渡せばいい訳だけど、その中で例外を発生させて、かつ、コミットしたい場合があった。
以下、イメージ。
ActiveRecord::Base.transaction do # 何かしらの処理 if a_conditions1 # 何かしらの処理 record.save! if a_conditions2 raise MyError.new end end end
このままだと、save!後の例外発生でロールバックしてしまう。ロールバックされないように例外を発生させることはできないのか、と調べてみたが、結論、見つからなかった。
結局、以下のようにしたが、
ActiveRecord::Base.transaction do # 何かしらの処理 if a_conditions1 # 何かしらの処理 record.save! if a_conditions2 error = MyError.new end end end raise error if error.present? # トランザクションの外に出した。
以下のように例外をラップしてくれて、コミット後、ラップされた例外をraiseしてくれるようなもの(ActiveRecord::NoRollback)がフレームワークに用意されててもいいのになあと思う。
ActiveRecord::Base.transaction do # 何かしらの処理 if a_conditions1 # 何かしらの処理 record.save! if a_conditions2 raise ActiveRecord::NoRollback.new(MyError.new) end end end
なお、transactionメソッド内のソースは以下となっている。
普通はelseが処理されてwithin_new_transactionメソッドが呼ばれる。rescueして亡き者にするのはActiveRecord::Rollbackのみ。
rescueされたら必ずロールバックされてしまう。ここでActiveRecord::NoRollbackの場合はロールバックしないようにしてくれたらいいのだけどなー。そんな単純な話ではないのだろうか。
Rubyのローカル変数が宣言されるタイミング
私はJavaから入ったのでいつも違和感がある。Rubyの場合はソースを上から解析していって、実行されなかったとしても変数宣言されているコードが存在していれば実際に宣言される。
if false a = 1 end p a #=> 1
以下のようにしたくなる。
a = nil if false a = 1 end p a #=> 1
transactionメソッドに出てきた以下のようなコードも違和感。
begin rescue Exception => error ensure unless error # end end
慣れだけの問題だけど。
Arelについて
そろそろ学んだ方がいいのかな、と調べたところ、
Arelでクエリを書くのはやめた方が良い5つの理由(Rails 5.0以前の場合)を読んで今はやめようと思いとどまった。
学ぶのはRails5.1がリリースされてからだ。
今日の所感
- 久々にブログを書いたら、ちょっとした記事なのにめっちゃ時間かかる。
- 従業員への要求が鏡のように自分に返ってきて勉強しなくっちゃという意欲(プレッシャー?)に変わる。
- 久々に与沢翼の動画を見て少し感動した。彼のまっすぐなところは好きだ。
- 去年から株と投資信託に手を出した。勧めてくる営業マンに好感を持ったからという理由だけで購入した。でも与沢翼の動画を見て、ちょっと調べてみることにした。
- 従業員のソースレビューをした。2メソッドで1ページ半くらいのボリューム。動けばいい、というのは嫌なのできっちりレビューしたら、その修正に3時間以上かかった。必要以上な修正指示を出してしまったのかと今でも揺れている。コードが綺麗だからといってそれだけでお金を生む訳ではない。結局、動きさえすればお金を生んでくれる。修正に1時間程度かかるレベルのレビューだけをして、残りの2時間は新規のコード作りに費やした方がよかったのだろうか。