views:

469

answers:

2

I'm using the rubyist-aasm state machine for handling the different states in my Event object (event initialized, event discussed, event published, etc.). I added guards to prevent state changes when certain conditions aren't met.

This all works fine but it doesn't show any errors when a state change was rejected by the guard. Any idea how I can see the state didn't change? I could check the states manually but it sounds like an ugly solution.

aasm_state :firststate 
aasm_state :secondstate  

aasm_event :approve do
  transitions :to => :secondstate, :from => [:firststate], :guard => :has_a_price? 
end

def has_a_price?   
  self.price.present?
end
A: 

I know in rubyist-aasm 2.0.2 you can call add '!' to the transition method call which will return false if the transition failed. So lets say you have a controller method named approve:

def approve
  @event = Event.find params[:id]

  if @event.approve!
    # transition occurred
  else
    # handle the failed transition (flash or errors)
  end
end

Let me know what you think?

tsdbrown
Thanks, this would work in the controller but I would like to keep these things in the model. With your solution I could still use the transition in another model without passing validation.
Cimm
Ah, ok. IMO the guard isn't really a validation error as far as the AR model is concerned though, it's a guard that simply protects the transition from occurring on the state machine, I personally would be happy with calling the ! method (in another model or controller) and checking the return. You can't 'see' something if you don't ask right? I could be completely wrong here so I'll be happy to see if any other solutions crop up. If you really want a validation error too you could add something like validates_presence_of :price, :if => "self.second_state?"
tsdbrown
A: 

With SimpleStateMachine you can guard state transitions by adding errors:

def approve
  errors.add(:price, 'Invalid') if price.blank?
end
event :approve, :firststate => :secondstate

Although in this case the price being present isn't related to the event so it would be enough to do:

validates_presence_of :price, :if => "self.second_state?"
event :approve, :firststate => :secondstate