44126


Ruby において、 block の中の break や return は、その block が定義された時の method call
をただちに終了させる効果があると理解しました。

この場合ふと次のことが気になりました：

  1. block の中で break や return が呼ばれる可能性によって、 block を yield する method は、どうがんばっても、 ensure 的に最後に実行する処理というものは記述できない。
  2. rails における `ActiveRecord::Base.transaction` は block を引数(厳密にはちがうけれども)にとって、その中身を transaction の文脈で yield している(はずだ)と理解できるけれども、しかし 1. を考慮すれば、開始した Transaction を確実に終了 (commit もしくは rollback によって) させるようなコードは transaction メソッドの中では記述できない

そうすると次の疑問が発生します。

### 質問

  * rails において、 `ActiveRecord::Base.transaction` の block の中で直接、 break や return を実行した場合においては、その transaction メソッドの Database に対する操作はどのようなものになりますか?可能性として以下がありうるかな、と思っています。 
    * commit される
    * rollback される
    * transaction が開始され、その commit/rollback のどちらも行われない中途半端な状態になる
    * ~~宇宙の法則が乱れて、~~ active record の動作が未定になる
    * ...


CC BY-SA 4.0
2018-05-11T05:34:49.373
43909
2018-05-21T07:20:06.723
754
question
ruby-on-rails ruby rails-activerecord
ActiveRecord::Base.transaction の最中に return すると何が起こる?


どうやら、自分が思い違いをしていた様子です。 block 中の break/return であっても、それによって外へ抜けられてしまう ensure
節はたしかに確実に実行されている様子です。なので、 transaction も、そのように ensure でもって確実に実行されるコードを実行し、
transaction の管理を行っているのではないか、と推測しています。

[code]

    class Foo
      def test_return
        yield_with_ensure do
          return
        end
        puts "returning test_return"
      end
    
      def test_break
        yield_with_ensure do
          break
        end
        puts "returning test_break"
      end
    
      def yield_with_ensure
        begin
          yield
          puts "after_yield"
        ensure
          puts "hoge ensured!"
        end
      end
    end
    
    puts "testing return"
    Foo.new.test_return
    
    puts "testing break"
    Foo.new.test_break
    
[/code]

### 出力

[code]

    testing return
    hoge ensured!
    testing break
    hoge ensured!
    returning test_break
    
[/code]


CC BY-SA 4.0
2018-05-21T07:20:06.723
44126
2018-05-21T07:20:06.723
754
43909
answer