在rails中将多个查询链接在一起时,如何很好地处理异常?

时间:2015-06-09 08:33:16

标签: ruby-on-rails ruby ruby-on-rails-4 exception-handling rails-activerecord

在我的几个控制器中,我的代码看起来像这样:

@user
  .cars.find_by_id(params[:car_id])
  .try(:wheels).find_by_id(params[:wheel_id])
  .try(:screews).where(id: ids)

这当然可以引发异常:NoMethodError:未定义的方法`where'为零:NilClass。我希望能够向我的用户提供有关错误的更多信息,在这种情况下,用户没有指定ID的汽车。

将find_by_id更改为find将导致上述代码引发我可以处理的ActiveRecord :: RecordNotFound异常,但在这种情况下,如何查明车辆或车轮是否丢失? RecordNotFound异常并不真正包含那么多信息。有没有什么好方法可以很好地处理这类事情?最好是一些通用的东西,我可以轻松地在我的其他控制器中重用代码。

2 个答案:

答案 0 :(得分:0)

ActiveRecord :: RecordNotFound异常有一条消息,即无法找到id = 200 的用户,因此您可以使用它来告诉您哪个模型未找到。

只需救出该异常并使用该消息向用户显示该信息。您可以在消息中搜索模型名称,并根据需要显示自定义提示。

答案 1 :(得分:0)

我会说你的代码闻起来,你应该重构它。

  
      
  • 每个单位应该对其他单位的知识有限:只有单位"密切关注"与当前单位有关。
  •   
  • 每个单位只应与其朋友交谈;不要和陌生人说话。
  •   
  • 只与您的直接朋友交谈。
  •   
     

http://en.wikipedia.org/wiki/Law_of_Demeter

我并不是说你需要崇拜得墨忒耳法(DHH has a pretty good post about this)或其他CS概念,而是在这种情况下捕捉异常不会使情况更好但是就像建立一个安全网围绕着一个基础较浅的塔楼,以便当居民崩溃时可以跳出窗户。

让我们逐行浏览:

@user
  .cars.find_by_id(params[:car_id])
  .try(:wheels).find_by_id(params[:wheel_id])
  .try(:screews).where(id: ids)

.find_by_id是一种所谓的动态查找器方法,它依赖于丢失的方法,它们从Rails 4中的核心中提取出来。使用.find代替它,它是向前兼容的并且没有开销该方法缺少了超魔法。

我们不需要从@user查询我们的查询范围,因为我们已经拥有汽车的唯一ID。

Car.find(params[:car_id])
  .try(:wheels).find_by_id(params[:wheel_id])
  .try(:screews).where(id: ids)

如果我们想要同时获取CarWheel,我们应该使用连接查询来进行有效的SQL查询。

Car.joins(:wheels)
   .where(id: params[:wheel_id])
   .find(params[:car_id])

但如果我们真正需要的是螺丝,我们可以这样做:

# Doing a JOIN to cars requires a 
# has_many :cars, through: :wheels relationsship
@screws = Screw.where(id: ids).joins(:cars, :wheels)

重申:

  • 当您拥有唯一ID时,请不要通过父级查询范围 - 您只有causing a N+1 query
  • 使用joins创建更有效的查询。
  • 使用例外来处理特殊情况,而不是正常的程序流程。