views:

101

answers:

3

I'm running into problems implementing statuses for a model. This is probably due to wrong design.

There is a model which has a status. There can be multiple instances of the model and only a few predefined statuses (like: created, renewed, retrieved etc.). For each individual status there is some calculation logic for the model. E.g. model.cost() is differently calculated for each status.

I'd like to have ActiveRecord automatically set the correct model_status_id when saving a model. I think in the ideal situation I could do something like this:

model.status = StatusModel.retrieved

and

case status
  when renewed
    # ...
  when retrieved
    # ..
end

Thinking i need to save the status in the model row in the database this is what i've got now:

ModelStatus < ActiveRecord::Base
  has_many :models
Model < ActiveRecord::Base
  belongs_to :model_status

However this is giving me a lot of issues in the code. Anyone having some good ideas or patterns for this?

+1  A: 

Why not keep the status part of the actual model? If they are predefined, that's not too much work:

class Model < ActiveRecord::Base

  STAT_CREATED   = 1 
  STAT_RENEWED   = 2
  STAT_RETRIEVED = 4

  validates_inclusion_of :status,
                         :in => [1, 2, 4]


  def created?
    status & STAT_CREATED
  end

  def renewed?
    status & STAT_RENEWED
  end

  def retrieved?
    status & STAT_RETRIEVED
  end

end

This way, you could either test the model instance directly (e.g. if @model.created?) or write your case statements like that:

case @model.status
when Model::STAT_CREATED
...
when Model::STAT_RENEWED
...
cite
Thanks a lot! Looks pretty logical. I sometimes just think way too complex.
benvds
A: 

Also try taking a look at the acts_as_state_machine plugin. I recently used it on a project and it worked well.

Bob Nadler
A: 

What you describe seems like a perfect case for a state machine.

There are many Ruby state machine implementations. You can see a fairly representative list at ruby-toolbox

When defining a state machine you can define several States and transitions. Each transitions taking your model from one state to another executing some code along the way. The DSL for it is usually quite nice.

Your example would look like

model.retrieve!

This will change the mode status from whatever it was to retrieved or throw an exception if current status doesn't transition to retrieved.

Vitaly Kushner