Dave
Dave

Reputation: 11162

Time dependent Has and Belongs-to Many

I'm working on a rails app where the associations between data change with time. I've created a model for the associations:

   create_table :accounts_numbers do |t|
     t.integer :number_id
     t.integer :account_id
     t.date :start_date
     t.date :end_date

And, so far, I have a simple model

class Account < ActiveRecord::Base
    has_and_belongs_to_many :numbers, :through => accounts_numbers
end              

But instead of

@account.numbers

I need something like

@account.numbers_at(Date.new(2010,2,3))

I thought I could use :conditions, but I wouldn't haven't seen a way to tell has_and_belongs_to_many to create a parameterized field. I've also looked into named_scope, but that only seems to return accounts, not numbers.

More importantly, this pattern is going to cover many relationships in my code, so would there be a way to coin a time_dependent_has_and_belongs_to_many for use all over?

Upvotes: 2

Views: 134

Answers (2)

Dave
Dave

Reputation: 11162

After much more searching, I finally found out what to do; In the /lib dir of my project, I created a module, TimeDependent:

module TimeDependent
    def at(date)
        find(:all, :conditions=>["start_date <= ? AND ? < end_date"], date, date)
    end
end

So, my model becomes

require "TimeDependent"
class Account < ActiveRecord::Base
    has_many :accounts_numbers
    has_many :numbers, :through => :accounts_numbers, :extend => TimeDependent
end    

Which allows me to do exactly what I want:

@numbers = @account.numbers.at(Date.new(2010,2,3)); 

Upvotes: 1

Mizuho
Mizuho

Reputation: 90

Couldn't this be done by writing a function for Object?

class Object
  def numbers_at(time)
    start = time.to_date
    end = time.advance(:days => 1).to_date

    AccountNumber.join(:accounts, :numbers).where("time BETWEEN(?, ?)", start, end)
  end
end

Upvotes: 0

Related Questions