class ApplicationController < ActionController::Base protect_from_forgery private def current_cart Cart.find(session[:cart_id]) rescue ActiveRecord::RecordNotFound cart = Cart.create session[:cart_id] = cart.id cart end end
由于我是一名Java开发人员,我对该部分代码的理解或多或少是以下内容:
private Cart currentCard(){ try{ return CartManager.get_cart_from_session(cartId) }catch(RecordNotFoundEx e){ Cart c = CartManager.create_cart_and_add_to_session(new Cart()) return c; } }
那是什么让我感到异常处理用于控制正常的应用程序流程(当用户第一次访问Depot应用程序时,缺少购物车是完全正常的行为).
如果有Java书籍,他们会说这是一件非常糟糕的事情,而且很有道理:错误处理不应该被用作控制语句的替代品,对于读取代码的人来说,这是一种误导.
有没有什么好的理由为什么这样的做法在Ruby(Rails)中是合理的?这是Ruby的常见做法吗?
解决方法
if something.save # formulate a reply else # formulate an error reply,or redirect back to a form,or whatever end
即保存返回true或false.但也有保存!这引发了一个异常(在方法名称的末尾添加一个感叹号是一个Rubyism,用于显示一个方法是“危险的”或破坏性的,或者简单地说它具有副作用,确切的含义取决于上下文).
为什么find引发异常有一个有效的原因,但是如果RecordNotFound异常冒泡到顶层,它将触发404页面的渲染.由于您通常不会手动捕获这些异常(在Rails应用程序中您很少看到救援ActiveRecord :: RecordNotFound),您可以免费获得此功能.在某些情况下,当某个对象不存在时,您需要执行某些操作,在这种情况下,您必须捕获该异常.
我不认为术语“最佳实践”实际上意味着什么,但是我的经验是,异常不用于控制Ruby中的流程,而不是Java或任何其他使用的语言.鉴于Ruby没有检查异常,所以您一般处理异常.
最后是解释.由于find最常见的用例是检索对象以显示它,并且该对象的URL将由应用程序生成,所以很可能是不能找到对象的特殊情况.这意味着应用程序正在生成到不存在的对象的链接,或者用户手动编辑了URL.也可能是对象已被删除,但是它的链接仍然存在于缓存中,或者通过搜索引擎,我会说这也是一种特殊情况.
该参数适用于在您的示例中使用,即使用ID.还有其他形式的查找(包括许多find_by_ *变体)实际搜索,并且那些不引发异常(然后在Rails 3中有哪些,它替代了在Rails 2中的许多用途).
我不是说使用例外作为流程的控制是一件好事,只是发现引发异常并不一定是错误的,而你的具体用例不是常见的情况.