Mixin behavior


#1

Hi, all,

I need to DRY up some code in a few models. My first inclination,
having come from the Java world, was to go with an abstract class.
After a bit of reading, I then decided to follow the mixin route
instead. Now I’m running into trouble, most likely from a few basic
misunderstandings.

There are three models I will be using to average and count rating
data by executing a scheduled job. Basically, I want to get averages
and counts for the last week, the last month, and all time, and dump
the data into isolated tables to allow for quick reads. The logic is
pretty much identical for each instance. I just have a variance of
dates and a different table for each set of summary data. So I
defined a module (messy, I know):


module RatingTotals::StoryRatingTotals

def refresh_story_totals(date = Date.new(2007, 1, 1))
# Removed most the code.
ratings = Rating.find(:all,
:select => 'rateable_id, AVG(rating) as
average_rating, COUNT(id) as count ',
:conditions => ["rateable_type = ‘story’ AND
created_at >= ? ", date],
:group => 'rateable_id ')

totals = []
ratings.each do |rating|
  totals << self.new(:story_id => rating.rateable_id,
                     :rating => rating.average_rating,
                     :count => rating.count)
end

self.transaction do
  self.delete_all
  totals.each do |total|
    total.save
  end
end

end
end

Then my models are pretty simple. I’d like to get a better aliasing
technique in place, but this at least executes:


class AllTimeStoryRatingTotal < ActiveRecord::Base
belongs_to :story

extend StoryRatingTotals

def self.refresh_totals
self.refresh_story_totals
end
end

class WeeklyStoryRatingTotal < ActiveRecord::Base
belongs_to :story

extend StoryRatingTotals

def self.refresh_totals
self.refresh_story_totals(1.week.ago)
end
end

class MonthlyStoryRatingTotal < ActiveRecord::Base
belongs_to :story

extend StoryRatingTotals

def self.refresh_totals
self.refresh_story_totals(1.month.ago)
end
end

When testing through the console, I can only execute a single one of
the class methods ( e.g. MonthlyStoryRatingTotal.refresh_totals).
Whichever class method I invoke first can be executed ad naseum, but
if I try to execute one of the other class refresh_totals methods they
are blocked out with the most classic of error messages:


ArgumentError: RatingTotals is not missing constant StoryRatingTotals!

What I suspect is that I’m confused on my ability to use ‘self’ within
modules. Another thought is that the way scoping works under the
console may not be true to real life. Though I also attempted to pass
in the class type as a parameter and I received the same errors.

Any thoughts on the most elegant way to abstract these class methods
successfully?

Thanks,