如何干这个代码?

时间:2013-09-12 14:10:39

标签: ruby-on-rails ruby-on-rails-3 dry helper

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

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

2 个答案:

答案 0 :(得分: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

答案 1 :(得分:1)

对于这个非常具体的方法,您可以使用@delba answer。

要准确回答有关跨模型共享方法的问题,那就是concern作业。

在rails-4中,关注点成为顶级公民,并自动创建目录app/models/concernsapp/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模块放在该目录中。