ActionController::Base rescue_from ActionController::RoutingError, :with=>:render_404 private def render_404(exception = nil) if exception logger.info"Rendering 404: #{exception.message}" end render :file=>"#{Rails.root}/public/404.html", :status=>404, :layout=>false end
异常处理是开发过程中经常要面对的问题,基本所有高级语言都有自己的异常处理系统,ruby也不例外,而且使用起来也非常简单。
ruby中异常的抛出是使用的raise方法,记住哦,这是个方法,由ruby Kernel提供的,而不是关键字,同时ruby也为这个方法提供了一个别名fail,可以用fail代替raise,抛出异常的例子如下:
raise #抛出一个默认的RuntimeError raise "Some error message" #抛出一个消息为"Some error message"的RuntimeError raise ArgumentError #抛出一个无消息的ArgumentError raise ArgumentError, "Bad data" #抛出一个消息为"Bad data"的ArgumentError raise ArgumentError.new("Bad data") #同上 raise ArgumentError ArgumentError, "Bad data", caller[0] #抛出一个包含消息的格式为filename:line 或者 filename:line:in 'method' 的异常
以上代码中的raise可以使用别名fail代替,在没有明确的给出异常类型时,ruby默认抛出RuntimeError,其中最后一个例子抛 出的信息包含了当前错误所在的文件,行数已经所在的方法的信息,这些信息都存储在caller这个数组中,里面包含了方法调用者的相关信息,第一个元素包 含了方法的调用者的信息,第二个信息包含了方法调用者的调用者的信息,以此类推。这个数组在我们想知道异常是在哪个地方的哪个调用被抛出的时候非常有用 的。
def func1 puts caller #打印调用者信息 end def func2 func1 #第六行 end def func3 func2 #第十行 end func3 #最终调用者,十三行#运行结果
#test.rb:6:in `func2'
#test.rb:10:in `func3'
#test.rb:13
从上面的代码可以看出,caller记录了每个调用者所在的文件名,行数以及方法。
上面讲解了关于ruby异常抛出的方式以及caller数组的作用,接下来我们来了解一下ruby中是如何进行异常的捕捉的,在java中,异常 的捕捉是在try ... catch当中进行,而ruby则是在begin ... end代码块中进行异常的捕捉,在该代码块中使用rescue关键字进行捕捉异常类型,注意哦,这个是关键字,而不是方法。
begin ...... #可能出现异常的代码 rescue errorType1 #要捕捉的异常类型 ...... #处理异常的代码 rescue errorType2 #要捕捉的异常类型 ...... #处理异常的代码 end
以上代码就是一个大概的捕捉异常的例子,在begin和end代码块中通过rescue进行异常类型的捕捉然后进行适当的处理,可是如果抛出的异常类型并没有显示的捕捉如何处理呢?那就是在最后使用else,如下:
begin ...... #可能出现异常的代码 rescue errorType1 #要捕捉的异常类型 ...... #处理异常的代码 rescue errorType2 #要捕捉的异常类型 ...... #处理异常的代码 else ...... #如果以上代码类型都没有捕捉到,则运行该段代码 end
这时又有一个问题,如果我想获取异常信息又该如何做呢?请看下面的代码:
begin raise ArgumentError, "Bad data" rescue => err puts err end
通过rescue => variable的方式,就可以将异常保存为一个variable了。又解决了一个问题,还有什么问题呢?啊,对了,在java的使用当中,比如使用 Connection进行数据库连接后,最后一定要进行资源的清理,都是在finally块当中进行的,可是在ruby中又如何进行这些资源的清理呢?看 看下面的代码:
begin raise ArgumentError, "Bad data" rescue => err puts err ensure ... #执行清理工作 end
从上面代码我们看到,ruby提供了一个关键字ensure,它的作用和java中的finally一样,无论任何异常,该关键字下的代码都必然 会在退出代码块前执行。同时,ruby还提供恢复功能,如果在抛出异常并进行异常处理后我们需要进行恢复工作,那就是使用retry就会重新执行代码块 了。
上面提到,异常的捕捉处理必须在begin-end代码块中进行,那是不是无论什么时候都要书写begin-end这两个关键字呢?其实也不是,在 ruby中,方法实际上就是一个隐式的begin-end代码块,所以在方法中进行异常的捕捉和处理,可以省略begin。