2

我的几个模型中有以下代码行:

def average(scores)
  # get average of scores and round to two decimal places
  average = scores.inject{ |sum, el| sum + el }.to_f / scores.size
  average.round(2)
end

我试图将它放入各种帮助文件中,并取得了不同程度的成功 - 但问题不在于我无法工作,而在于它需要一些丑陋的代码和/或额外的文件(模块等)才能包含在所有模型中都采用这种方法——这引发了一些危险信号。它不应该那么难。

辅助代码对于控制器和视图来说很容易,但对于模型来说似乎真的违反直觉——同时,在 4 个地方(字面上)拥有完全相同的代码似乎很愚蠢。把它弄干的最好方法是什么?

更新

我想average在每个模型的方法中使用帮助器 - 在每种情况下都是不同的,但对于所有内容的最后一行 - 就像这样:

def avg_for(student)
  scores = []
  self.evals.map do |student_id, evals|
    evals.select {student_id == student.id}.each do |eval|
      scores << eval.score
    end  
  end    
  average(scores) #here!
end
4

2 回答 2

2

http://api.rubyonrails.org/classes/ActiveRecord/Calculations.html#method-i-average

class Student < ActiveRecord::Base
  has_many :evals

  def average_score
    evals.average(:score)
  end
end

在 Rails 之外:

def average(score)
  (score.inject(:+).to_f / score.size).round(2)
end

编辑

用你的avg_for方法:

def avg_for(student)
  evals.where(student: student).average(:score)
end
于 2013-09-12T14:16:32.253 回答
1

对于这种非常具体的方法,您可以使用@delba 答案。

要准确回答您关于跨模型共享方法的问题,这是一项令人担忧的工作。

在 rails-4 中,关注点成为顶级公民,目录app/models/concerns和目录app/controllers/concerns是自动创建的。

您可以在以下位置添加类似的内容app/concerns/averageable.rb

module Averageable
  def average(scores)
    # get average of scores and round to two decimal places
    average = scores.inject{ |sum, el| sum + el }.to_f / scores.size
    average.round(2)
  end
end

然后,在您的模型中使用它:

class User < ActiveRecord::Base
  include Averageable
end

您关注的方法将可用于包含它的任何模型。

编辑 :

要在 rails-3 中执行相同的操作,请将您想要关注的路径添加到config.autoload_paths、 中config/application.rb

config.autoload_paths += %W(#{config.root}/lib/concerns)

并将averageable.rb模块放在该目录中。

于 2013-09-12T14:28:32.943 回答