Padrino のエラー処理と後処理

最近 Padrino というウェブアプリケーションフレームワークを触ってます。

Padrino ではコントローラーのアクションを実行する前後に処理を実行することができます。

    before do
      前処理
    end

    after do
      後処理
    end

    get :hoge do
      処理
    end

また、エラー時に表示されるページを指定することができます。

    error 403 do
      render 'errors/403'
    end

    error 404 do
      render 'errors/404'
    end

    error 500 do
      render 'errors/500'
    end

ですが、エラー時に after が実行されない場合があったので調べてみました。

その1. コントローラーが見つからない場合

コントローラーが見つからない場合は、404 Not Found エラーになるのですが、error 404 は実行されません。 また after も実行されません。

プログラム内で halt 404 を行った場合は error 404 も after も実行されます。

error 404 の代わりに not_found を使えばコントローラーが見つからなかった場合にも実行されますが、after は実行されません。

after で行いたい後処理を not_found の中にも書いておけばいいのですが、そうすると今度は halt 404 を行った場合に後処理が二回実行されてしまいます。

not_found の後に error 404 を定義すると、halt 404 では not_found は実行されないので次のように記述することができます。

    after do
      後処理
    end

    # コントローラーが見つからない場合。
    # after は実行されない。
    not_found do
      後処理
      render 'errors/404'
    end

    # プログラム中で halt 404 した場合。
    # after は実行される。
    error 404 do
      render 'errors/404'
    end

なお not_found の前に error 404 を書くと error 404 は実行されません。 記述する順番に依存するのはややこしいので not_found を使わない方がいいかもしれません。

error Sinatra::NotFound はコントローラーが見つからない場合にだけ実行され、halt 404 時には実行されないので、記述する順番には依存しません。

    after do
      後処理
    end

    # プログラム中で halt 404 した場合。
    # after は実行される。
    error 404 do
      render 'errors/404'
    end

    # コントローラーが見つからない場合。
    # after は実行されない。
    error Sinatra::NotFound do
      後処理
      render 'errors/404'
    end

その2. プログラム中で例外が発生した場合

プログラム中で例外が発生した場合にも after は実行されません。

development 環境では after は実行されるのですが、これは development 環境では :show_exceptions が true になっているためです。

production 環境と同じ動作をさせるために次のように設定すると、development 環境でも after が実行されないことが確認できます。

    disable :show_exceptions

例外発生時は 500 エラーになるので error 500 を書いておけばそれが実行されます。

not_found の時と同様、プログラム内で halt 500 すると after と error 500 の両方で後処理が実行されてしまいますが、プログラム中からわざわざ halt 500 を行うことはないと思うので、問題ないでしょう。

    after do
      後処理
    end

    # halt 500 の場合 & 例外が発生した場合。
    error 500 do
      後処理
      render 'errors/500'
    end

error に数字ではなく例外クラスを指定すると、その例外が発生した時だけ実行できるので、次のようにも記述できます。 この場合は halt 500 では実行されません。

    after do
      後処理
    end

    # 例外が発生した場合。
    # after は実行されない。
    error Exception do
      後処理
      render 'errors/500'
    end

なぜか error Exception が nil を返す場合は after が実行されるので、後処理を実行したいだけであれば次のように記述することもできます。 ただしこの場合は 500 のエラーページを返すことはできません。

    after do
      後処理
    end

    # 例外が発生した場合。
    # after が実行される。
    error Exception do
      nil
    end

まとめ

  • 例外発生時は after は呼ばれない
  • not_found は halt 404 とコントローラーが見つからない場合の両方で呼ばれる
  • error 例外クラス で例外発生時の処理を記述できる