Railsã®ã³ã³ããã¼ã©ã§ã®ä¸å¯è§£(ã«è¦ãã)ãªã¨ã©ã¼ãã³ããªã³ã°ã«ã¤ãã¦
ãã£ã±å®¶ã§ããªãããé©å½ãªcontrollerã«
— snocchy (@snocchy) 2018å¹´4æ19æ¥
def index
raise ActiveRecord::RecordNotFound # (1)
rescue
raise 're-raise' # (2)
end
ã¨ãæ¸ãã¦ãã©ã¦ã¶ããéãã¨ä½æ ã(1)ã§æ»ãã ãã¨ã«ãªã£ã¦ããã³ã³ã½ã¼ã«ããå©ãã¨(2)ã«ãªããraiseããã®ãActiveRecordErrorã«ããã°ã©ã¡ãã(2)
Twitterã§ãã®ãããªããã¨ããè¦ããã¦ãæ°ã«ãªã£ã¦ç ããªãã£ãã®ã§èª¿ã¹ã¦ã¿ãã é·ã£ãããã説æãã¦ããã®ã§çµè«ã ãç¥ãããæ¹ã¯ä¸ã¾ã§ã¹ã¯ãã¼ã«ãã¦ãã ããã
åé¡
æå ã§ããåããã Rails5.1.1 / Ruby 2.5.0ã§è©¦ããã
# controller class WelcomeController < ApplicationController def index raise ActiveRecord::RecordNotFound rescue => e raise 're raise' end end # config/route.rp Rails.application.routes.draw do root to: 'welcome#index' end
ãã®ç¶æ ã§WEBã«ã¢ã¯ã»ã¹ããã¨ãããªã!!
ï¼ï¼ raise re raise
ã«ãªããã»ã»ã»ã¾ãã
rescueããã¦ãªãããã«ã¿ããã
ã¡ãªã¿ã«ãããã³ã³ã½ã¼ã«ã§ããã¨ãããªã
ã³ã³ã½ã¼ã«ã ã¨ã¡ãã㨠âre raiseâ ãä¾å¤ã«ãªãï¼ï¼
次ã«ã³ã³ããã¼ã©ã®ä¾å¤ãRecordNotFoundã§ãªããã¦ã¿ã
# controller class WelcomeController < ApplicationController def index raise ActiveRecordError rescue => e raise 're raise' end end
ããã¨ã¡ãã㨠re raise
ã®æ¹ãä¾å¤ã¨ãã¦ä¸ãã£ã¦ããâ¦ä¸å¯è§£
種æãã
rescueããã¦ãªãããè¦ããããæ¬å½ã«ããã¦ãªãã®ã ãããã
binding.pry
ãä»æãã¦ã¿ãã
class WelcomeController < ApplicationController def index raise ActiveRecord::RecordNotFound rescue => e binding.pry raise 're raise' end end
ããã»ã»ã»ã¡ããã¨rescueããã¦ã¾ããã»ã»ã» ã¨ãããã¨ã¯ãç»é¢ä¸ã®è¡¨ç¤ºãããããã®ã ããã
lib/action_dispatch/middleware/debug_exceptions.rb @ line 68 ActionDispatch::DebugExceptions#call: 57: def call(env) 58: request = ActionDispatch::Request.new env 59: _, headers, body = response = @app.call(env) 60: 61: if headers["X-Cascade"] == "pass" 62: body.close if body.respond_to?(:close) 63: raise ActionController::RoutingError, "No route matches [#{env['REQUEST_METHOD']}] #{env['PATH_INFO'].inspect}" 64: end 65: 66: response 67: rescue Exception => exception => 68: raise exception unless request.show_exceptions? 69: render_exception(request, exception) 70: end [1] pry(#<ActionDispatch::DebugExceptions>)> exception => #<RuntimeError: re raise>
render_exception
ã¨ããã¨ã©ã¼ãã¼ã¸ãçæãã¦ããã¨ããã¾ã§ã¡ãã㨠re raise
ã®ã¨ã©ã¼ã渡ã£ã¦ãã¦ãã¾ããã
ã§ã¯ render_exception ã®ä¸èº«ãè¦ã¦ããã¾ããã
# actionpack-5.1.1/lib/action_dispatch/middleware/debug_exceptions.rb 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.new
ãæªããããããã«ãã®ã³ã¼ãã追ã£ã¦ã¿ã¾ãã
# actionpack-5.1.1/lib/action_dispatch/middleware/exception_wrapper.rb 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 ) # ãããçç¥ãããã 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 # ãããçç¥ãããã private def original_exception(exception) if @@rescue_responses.has_key?(exception.cause.class.name) exception.cause else exception end end # ãããçç¥ãããã end
èªãã§ããã¨ä»¥ä¸ã®ãããªåãã«ãªã£ã¦ãããã¨ããããã¾ãã
initialize
ã§original_exception
ã¨ããã®ãå¼ã¶ãoriginal_exception
ã§ã¯exception.cause
ã§å ã çºçãã¦ããä¾å¤ãè¦ã«è¡ã- ããã
rescue_responses
ã«ä¸è´ããå ´åã«ã¯ããããExceptionWrapper
ã®exception
ã«ã»ãããã
ã§ããããã«ã¯ ActiveRecord::NotFound
ã«å¯¾å¿ãããã®ã¯ããã¾ããã
å®ã¯ããã§ã¯ãªãã¦ãActiveRecod
ã®æ¹ã§æ¡å¼µãè¡ããã¦ããããã§ãã(ã³ã¼ãã¡ããã¨ãã£ãããã§ã¯ãªããã©å¤åãã)
# activerecord-5.1.1/lib/active_record/railtie.rb module ActiveRecord # = Active Record Railtie class Railtie < Rails::Railtie # :nodoc: # ãããçç¥ãããã config.action_dispatch.rescue_responses.merge!( "ActiveRecord::RecordNotFound" => :not_found, "ActiveRecord::StaleObjectError" => :conflict, "ActiveRecord::RecordInvalid" => :unprocessable_entity, "ActiveRecord::RecordNotSaved" => :unprocessable_entity ) # ãããçç¥ãããã end
ããã¾ã§æ¥ã¦ãã£ã¨ãããã¾ãããä¾å¤ã®ãã®åã«çºçãã¦ããä¾å¤ããActiveRecord::RecordNotFound
ã®å ´åã«ã¯ãç»é¢ä¸ã«çºçããä¾å¤ãã®ãã®(ä»åã§ãã㨠re raise
)ã§ã¯ãªããå
ã
ã®ä¾å¤ã§ããActiveRecord::RecordNotFound
ã表示ããããã¨ããæåã«ãªã£ã¦ããããã§ãã
ãçµè«
å®éã«Tweetããã¦ãæ¹ã®ç°å¢ã確èªããããã§ã¯ãªãã®ã§å®å ¨ãªãæ¨æ¸¬ã§ããã以ä¸ã®ãããªç¶æ³ãªã®ã§ã¯ãªãã§ãããã
- ã¨ã©ã¼ãã³ããªã³ã°ã¯ãã¡ãã¨è¡ããã¦ãã
- ãããç¹å®ã®ä¾å¤ã®å ´åã«ã¯ãrescueç¯ã®ä¾å¤ã§ã¯ãªãããã®åã«çºçãã¦ããå ã ã®ä¾å¤ã®æ å ±ãç»é¢ã«è¡¨ç¤ºããã
- ä¸è¨ã®æåã«ãã
ActiveRecord::RecordNotFound
ãrescue
ããã¦ããªããããªä¸å¯è§£ãªæåã«è¦ãã
ã¡ãªã¿ã«ãã®æåã¯Rails3.2.0RCãããããã®ã®ããã§ãã
追è¨
ãã¨ãã¨ã®å®è£ ã¯ãã£ã¡ã https://t.co/DGtctOgyYz
— ãã¼ããäºå· (@suusan2go) 2018å¹´4æ20æ¥
åãæ°ã«ãªã£ãã®ã§èª¿ã¹ã¦ã¿ããã§ããå ã®ãã±ããã¨ã³ãããã¯ããã§ããhttps://t.co/yTBxoHM9f6https://t.co/lM1Y0LdoaA
— ããã° (@wakaba260yen) 2018å¹´4æ20æ¥
ä½ããã®ä¾å¤ãã©ããããä¾å¤ãè¿ãã¦ãã大æ¬ã®ã¨ã©ã¼ãrescue_responseã®å¯¾è±¡ã¨ãã¦ç»é²ããã¦ããrescue_responseãé©ç¨ããããã«ããããã«ãã¦ããã¿ããã§ã