2014-11-09 2 views
0

Я хочу вычислить компоненты среднегокаждый блок создать класс Nil

контроллер

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 

хорошо определен вне блока

+0

инициализируются вы '@ numerator' и' @ denumerator' '' ''? –

+0

Если я инициализирую, я получаю: ZeroDivisionError (деленный на 0) – clement

+0

@clement это другая проблема (с алгоритмом). –

ответ

0

.each При входе в цикл 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 равно 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 
0

Попробуйте инициализировать numerator и denumerator на номер, как ответ @ p11y в.

Мое предложение заключается в вычислении среднего более рубиновый так, как это:

@numerator = @evaluations.map { |e| e.average * e.coefficient }.reduce(&:+) 
@denumerator = @evaluations.map { |e| e.coefficient }.reduce(&:+) 
@average = @numerator/@denumerator 
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 

Надеется, что это приводит вас в правильном направление

Смежные вопросы