I’m using Rails 3.1, MySQL and working with 3 classes: Computer, LifecycleStatus & LifecycleEntry
I want to track the history of a Computer’s LifecycleStatus over time so the columns in LifecycleEntry are: computer_id:integer, lifecycle_status_id:integer and changed_at:datetime. A computer can have multiple entries in LifecycleStatus.
I have the following associations set up:
Computer
has_many :lifecycle_entries, :order => "changed_at DESC"
has_many :lifecycle_statuses, :through => :lifecycle_entries
LifecycleEntry
belongs_to :computer
belongs_to :lifecycle_status
LifecycleStatus
has_many :lifecycle_entries
I’d like to see, for a particular LifecycleStatus, which computers are currently (their most recent lifecycle_entries record) assigned to that status.
I’ve managed to create the correct SQL to retrieve this info, but am not sure how to translate this to a Rails association:
SELECT id, le.computer_id, lifecycle_status_id
FROM lifecycle_entries AS le
INNER JOIN (
SELECT lemax.computer_id, MAX(changed_at) AS latest
FROM lifecycle_entries AS lemax
GROUP BY lemax.computer_id
) maxdates
ON le.changed_at = maxdates.latest
AND le.computer_id = maxdates.computer_id
WHERE lifecycle_status_id = 6
It seems like this would be simpler if you denormalized the ‘active’ status onto the LifecycleEntry itself, updating it each time a new entry is created. This saves you a GROUP BY / MAX query each time you read.
If you have the status column it would be as simple as LifecycleEntry.active.where(:lifecycle_status_id => 6).computers, where active is a scope on LifecycleEntry.
So do the following:
activeboolean field toLifecycleEntryLifecycleEntrymodel to set the active entryHere is the callback:
It’s important to note that the LifecycleEntry being created may precede the currently active one, so you must only set the new one to active if the changed_at is after. Also, for the first LifecycleEntry created, active is always set.