【问题标题】:ActiveRecord: treat nil as a 0 in calculations?ActiveRecord:在计算中将 nil 视为 0?
【发布时间】:2017-09-17 19:39:34
【问题描述】:

我在我的控制器中使用此代码来访问Heavy 分类中所有用户的平均paper_weight

if User.where(industry_type: 'Heavy')
 .joins(:papers)
 .where(papers: { paper_type: 'Officepaper' } )
 .pluck('avg(paper_weight)').first.nil?
 @heavy_indust_officepaper == 0
else
@heavy_indust_officepaper = User.where(industry_type: 'Heavy')
 .joins(:papers)
 .where(papers: { paper_type: 'Officepaper' } )
 .pluck('avg(paper_weight)').first * 3 
end

然后变量@heavy_indust_officepaper显示在一个视图中。

问题在于,当一个或多个用户在 paper_type: 'Officepaper' 中有一个 nil 条目时,上面的代码似乎无法正确计算平均值。

我知道,因为我在 industry_type: 'Heavy' 中有两个用户 其中一个有一个paper_type: 'Officepaper' 的条目,即十进制30。 而另一个用户在paper_type: 'Officepaper' 中有nil 条目。

根据我的理解计算应该是30 + 0 / 2(users) = 15

然后15 乘以3 应该得到45

但是变量@heavy_indust_officepaper在视图中显示90...这一定是30 * 3的结果

有没有办法在上面的代码中将nil转换为0???

有人可以给我建议吗?

这是我今天早些时候提出的一个问题的链接,我从中获得了有关此代码的帮助 Using .average with .pluck in ruby on rails app?

【问题讨论】:

  • 你试过nil.to_i吗?在irb 中尝试它...而不是使用.first.to_i * 3 ...只是一个想法...
  • 你为什么要运行两次相同的查询而不是使用局部变量?
  • 如果在给定的答案中有解决您的问题的答案,请确保选择并接受答案。

标签: ruby-on-rails ruby ruby-on-rails-4 activerecord ruby-on-rails-5


【解决方案1】:

这里的问题(除其他外)是您对pluck 所做的事情的误解。它为您返回每个用户的平均 someting 数组。所以在你的例子中它会返回你

[30, nil]

这就是你得到90 ([30, nil].first * 30 => 90) 的原因。

要获得所有用户的平均值,请使用average


解决方案:

您可以在计算平均值时使用COALESCENULL 转换为零:

User.where(industry_type: 'Heavy')
    .joins(:papers)
    .where(papers: { paper_type: ['Officepaper', nil] } )
    .average('COALESCE(papers.paper_weight, 0)') * 3
#=> 15

需要注意的一点是,虽然COALESCE 在计算时会将任何null 值转换为0,但如果没有记录,average 仍将返回nil计算average on。

如何处理这种情况由您决定,但 @max 已经展示了一个非常简单的选项(假设上述查询结果写入average 变量):

average.nil? ? 0 : average * 3

【讨论】:

【解决方案2】:
avg = User.where(industry_type: 'Heavy')
 .joins(:papers)
 .where(papers: { paper_type: ['Officepaper', nil] } )
 .average('papers.paper_weight')

@heavy_indust_officepaper = avg.nil? ? 0 : avg * 3

【讨论】:

  • avg ? avg * 3 : 0会更简洁一些。
  • @moveson avg&.* 3 更加简洁,但我认为简短不是重点:)
  • 同意,但是如果您要麻烦使用三元组,我认为您不妨摆脱额外的方法调用。我尽量不使用#nil?,除非与依赖评估为nil的变量的固有虚假性相比,它会产生明显更好的结果。
  • @moveson 正如@AndreyDeineko 已经说过的短不是重点。相反,.nil? 调用只是为了非常明显地表明正在发生的事情是一个 nil 检查。
  • 我明白短不是重点。我只是在 Ruby 样式指南中建议一种既干净又recommended 的样式。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-14
  • 1970-01-01
  • 2018-03-09
相关资源
最近更新 更多