Upgrade to Pro — share decks privately, control downloads, hide ads and more …

rescue されない例外?! / A Exception not rescue #megurorb

Kenta Suzuki
September 27, 2018

rescue されない例外?! / A Exception not rescue #megurorb

Meguro.rb #19 で話しました
https://megurorb.connpass.com/event/100401/

Kenta Suzuki

September 27, 2018
Tweet

More Decks by Kenta Suzuki

Other Decks in Programming

Transcript

  1. 6

  2. 7

  3. 8

  4. 10

  5. rails consoleで試してみる 12 irb(main):001:0> def fuga irb(main):002:1> raise ActiveRecord::RecordInvalid irb(main):003:1>

    rescue irb(main):004:1> raise 'piyopiyo' irb(main):005:1> end => :fuga irb(main):006:0> fuga Traceback (most recent call last): 3: from (irb):6 2: from (irb):1:in `fuga' 1: from (irb):4:in `rescue in fuga' RuntimeError (piyopiyo) irb(main):007:0>
  6. actionpack/lib/action_dispatch/middleware/debug_exceptions.rb 16 def call(env) request = ActionDispatch::Request.new env _, headers,

    body = response = @app.call(env) if headers["X-Cascade"] == "pass" body.close if body.respond_to?(:close) raise ActionController::RoutingError, "No route matches [#{env['REQUEST_METHOD']}] #{env['PATH_INFO'].inspect}" end response rescue Exception => exception invoke_interceptors(request, exception) raise exception unless request.show_exceptions? render_exception(request, exception) end エラー画面を表示して いる箇所はここ! exceptionはそのまま 渡している
  7. actionpack/lib/action_dispatch/middleware/debug_exceptions.rb 17 def render_exception(request, exception) backtrace_cleaner = request.get_header("action_dispatch.backtrace_cleaner") wrapper =

    ExceptionWrapper.new(backtrace_cleaner, exception) log_error(request, wrapper) if request.get_header("action_dispatch.show_detailed_exceptions") content_type = request.formats.first if api_request?(content_type) render_for_api_request(content_type, wrapper) else render_for_browser_request(request, wrapper) end else raise exception end end ExceptionWrapper 怪しい
  8. actionpack/lib/action_dispatch/middleware/exception_wrapper.rb 18 module ActionDispatch class ExceptionWrapper # 〜〜〜省略〜〜〜〜 def initialize(backtrace_cleaner,

    exception) @backtrace_cleaner = backtrace_cleaner @exception = original_exception(exception) expand_backtrace if exception.is_a?(SyntaxError) || exception.cause.is_a?(SyntaxError) end # 〜〜〜省略〜〜〜〜 end end original_exception!
  9. @@rescue_responsesはなにかというと 21 module ActionDispatch class ExceptionWrapper # 〜〜〜省略〜〜〜〜 @@rescue_responses.merge!( "ActionController::RoutingError"

    => :not_found, "AbstractController::ActionNotFound" => :not_found, "ActionController::MethodNotAllowed" => :method_not_allowed, "ActionController::UnknownHttpMethod" => :method_not_allowed, "ActionController::NotImplemented" => :not_implemented, "ActionController::UnknownFormat" => :not_acceptable, "ActionController::InvalidAuthenticityToken" => :unprocessable_entity, "ActionController::InvalidCrossOriginRequest" => :unprocessable_entity, "ActionDispatch::Http::Parameters::ParseError" => :bad_request, "ActionController::BadRequest" => :bad_request, "ActionController::ParameterMissing" => :bad_request, "Rack::QueryParser::ParameterTypeError" => :bad_request, "Rack::QueryParser::InvalidParameterError" => :bad_request )
  10. 再考 25 def fuga raise ActiveRecord::RecordInvalid rescue raise 'piyopiyo' end

    最終的にraiseされているのはこれ しかしエラー表示の際には、この例外の cause である ActiveRecord::RecordInvalidが表示さ れる
  11. まとめ 29 • この挙動はちょっとぎょっとしますが仕様です • 試してみたら、templateでのエラーは ActionView::Template::Errorで Wrapされる • このcauseを見に行く仕様は、templateでおもむろに

    `User.find(:id)` と かやってActiveRecord::RecordNotFoundがraiseされても、ちゃんと 404を返したりするためのものっぽい・・・・・・? • もともとの用途がtemplateでのエラーのためのものなので、causeを見 る挙動はActionView::Template::Errorに絞ってもよいのではという気が してきた。 • なんか間違ってるところあれば教えてください :pray: