Reputation: 11017
I have the following line of code in several of my models:
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
I've tried to put it in various helper files, with varying success - but the problem isn't that I can't getting working, it's that it takes some ugly code and/or extra files (modules, etc) just to include this method in all of models - and that's raising some red flags. It shouldn't be that hard.
Helper code is easy for controllers and views, but seems really counter-intuitive for models - at the same time, it seems silly to have (literally) the exact same code in 4 places. What's the best way to dry this out?
update
I want to use the average
helper inside of each model's methods - which are different in every case, but for the last line where everything is averaged - like so:
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
Upvotes: 2
Views: 190
Reputation: 27493
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
Outside of Rails:
def average(score)
(score.inject(:+).to_f / score.size).round(2)
end
Edit
With your avg_for
method:
def avg_for(student)
evals.where(student: student).average(:score)
end
Upvotes: 2
Reputation: 7937
For this very specific method, you can use @delba answer.
To answer exactly your question about sharing methods across models, that's a concern job.
In rails-4, concerns becomes top level citizen, and directories app/models/concerns
and app/controllers/concerns
are automatically created.
You can add something like that, in 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
Then, use it in your model :
class User < ActiveRecord::Base
include Averageable
end
The methods from your concern will be available for any model that includes it.
Edit :
To do the same in rails-3, add the path you want to put your concerns in into config.autoload_paths
, in config/application.rb
:
config.autoload_paths += %W(#{config.root}/lib/concerns)
And put the averageable.rb
module in that directory.
Upvotes: 1