I have a simple rails app with models project and phase. A project has many phases, but only on phase can be active (i.e. “current”) at a time. I still want the other phases to be accessible, but the current phase should be the main anchor for the application. The decision on how to implement this requirement has major implications on how I handle model access, validations and views / forms for creation update.
So the question is: How do I achieve this “has_many but has-only-one-current association” without adding too much complexity? Main goals being: simplicity in access of current phase + ensuring there cannot be more than 1 active phase at a time.
Naturally, I had some thoughts myself and came up with three options, which I want to present here. Any feedback on why I should choose one option over the other (or suggestion of a simpler solution) would be appreciated:
First Option:
[Project] has_many :phases
[Project] has_one :current_phase, :class_name => "Phase", :conditions => { :current => true }
Drawback: I have a nested form for creating projects and corresponding phases. There seems to be no easy way to set exactly one of the newly created phases as active
Second Option:
[Project] has an attribute "current_phase_id"
[Project] has_many :phases
[Project] belongs_to phase, :foreign_key => "current_phase_id"
Drawback: same as option 1, but I have another attribute and a belongs_to association, which seems weird (why should a project belong to one of its phases?)
Third Option:
[Phase] has an attribute "active" (boolean)
[Phase] scope :active, :conditions => { :active => true}
# Access to current phase via: project.phases.active
Drawback: I have to ensure via validations that there is only one active phase at a time, which is hard if multiple phases are created / edited at the same time OR during switch from one phase to another; plus: project.phases.active returns an array, if I’m not mistaken
Your help is greatly appreciated. Thanks!
Update
Added a bounty to encourage further opinions on the topic. Bounty will be awarded to the solution which best addresses the main goals expressed above; or if no alternative solution is mentioned, to the answer that best explains why I should favor one of the given options over the other. Thanks!
Why don’t you just add a date-time column called
activated_atto yourPhasemodel. Then set this to the current time whenever you want to make a phase active.At any given time, the phase with the latest
activated_atvalue is the current phase so you can just get it with@project.phases.order('activated_at DESC').first. Just wrap this in a method inProjectand you have a very concise representation: