每个块创建一个Nil类

时间:2014-11-09 10:07:57

标签: ruby-on-rails ruby

我想要计算平均值的组件

控制器

  def set_average_course
    @course = @group.courses.find(params[:course_id])
    @evaluations = @course.evaluations
    @evaluations.each do |evaluation|
      @numerator += evaluation.average * evaluation.coefficient
      @denumerator += evaluation.coefficient 
    end
    @average = @numerator / @denumerator
    @course.update(average: average)
  end

日志

NoMethodError (undefined method `+' for nil:NilClass)

但是

@numerator += evaluation.average * evaluation.coefficient

在.each块之外定义明确

3 个答案:

答案 0 :(得分:1)

使用SQL计算值会更好,更有效:

代码如下所示:

def set_average_course
  @course = @group.courses.find(params[:course_id])
  res = Evaluation.select("SUM(Evaluations.average * Evaluations.coefficient) AS numerator, SUM(Evaluations.coefficient) AS denumerator").
    where(course_id: @course.id)

  average = res.first['numerator'] / res.first['denominator'] # Raise an error if 0
  @course.update(average: average)
end

希望这能引导你走向正确的方向

答案 1 :(得分:0)

第一次进入each循环时,@numerator@denumerator尚未初始化。实例变量与局部变量的不同之处在于,如果尚未初始化,则它们将计算为nil,而对未初始化的局部变量的引用将引发错误。解决方案是在进入循环之前将变量初始化为加法的中性元素,即0

def set_average_course
  @course = @group.courses.find(params[:course_id])
  @evaluations = @course.evaluations
  @numerator = 0
  @denumerator = 0
  @evaluations.each do |evaluation|
    @numerator += evaluation.average * evaluation.coefficient
    @denumerator += evaluation.coefficient 
  end
  @average = @numerator / @denumerator
  @course.update(average: average)
end

虽然,作为旁注,我认为你的意思是"分母"而不是" denumerator"。您还必须考虑@denumerator等于0的情况,例如,当@evaluations为空时:

def set_average_course
  @course = @group.courses.find(params[:course_id])
  @evaluations = @course.evaluations
  return if @evaluations.blank?                       # or raise an error
  @numerator = 0
  @denumerator = 0
  @evaluations.each do |evaluation|
    @numerator += evaluation.average * evaluation.coefficient
    @denumerator += evaluation.coefficient 
  end
  @average = @numerator / @denumerator
  @course.update(average: average)
end

答案 2 :(得分:0)

尝试将numeratordenumerator初始化为@ p11y的回答。

我的建议是计算平均更多红宝石的方式:

@numerator = @evaluations.map { |e| e.average * e.coefficient }.reduce(&:+)
@denumerator = @evaluations.map { |e| e.coefficient }.reduce(&:+) 
@average = @numerator / @denumerator