application_controller.rb
に rescue_from
を書いて Exception を扱うことがよくあると思います。今日はこの優先順位でハマりました。最初はステータスコードの番号順だよねという単純な理由で以下のようにしていました。
rescue_from CanCan::Unauthorized, with: :render_403
rescue_from Exception, with: :render_500 if Rails.env.production?
render_500
の中ではエラーをメールで飛ばす処理とかが実装されているので、本番だけ動かすようにしていました。この指定で、開発環境では CanCan::Unauthorized
は正しく render_403
で拾うことができました。
ただ、このコードを production に載せると問題が発生しました。 CanCan::Unauthorized
は render_500
に行ってしまうのです。「テストも通っていたのになぜ……」と悩みましたが、どうやらこの指定は後に指定したものが優先されるようです。上記の指定では、 if Rails.env.production?
がついているせいで後に指定したものが無視されていました。
結論
CanCan::Unauthorized
を優先するため後に書き、 unless Rails.env.development?
に変えました。 こうしておくことで test と production を同じ動きにすることができ、正しくテストを落とせます。
rescue_from Exception, with: :render_500 unless Rails.env.development?
rescue_from CanCan::Unauthorized, with: :render_403