Hi all,
I have a Rails 3.1 application that uses the state_machine gem (https://github.com/pluginaweek/state_machine) to track a model's states. and the state_machine-audit_trail gem (https://github.com/wvanbergen/state_machine-audit_trail) to save the state changes.
#State Machine states for Work Orders
state_machine :initial => :created do
after_transition :on=>:validate, :do=>:create_report
store_audit_trail
event :validate do
transition :created => :validated
end
event :reject do
transition :created => :rejected
end
end
There is one particular state 'rejected' that is temporary, and I'm looking for a way to trigger an event to return the model to the previous state as saved in the WorkOrderStateTransition model (provided by the audit gem).
I created a method 'previous_state' that finds the last state transition, and when the method is called via console it doesreturn the previous state name.
The problem is I'm unable to call that method within the state_machine transition to use it as the destination state on a restore. To illustrate, something like this does not work:
event :restore do
transition :rejected => lambda {|wo| wo.previous_state}
end
What I get stored as a state is a Proc.
I would have thought this would be a pretty common use case (returning to a previously saved state) but I have found very little info while searching. The only post that is relevant is Using pluginaweek's state_machine, can I reference the activerecord object during an event? But this does not use the workflow history provided by the audit gem , and also returns the state to a 'restored' state, which is not what I need.
Has anybody come across this same use case? I'm somewhat new to Ruby/Rails and I realize this may be entirely due to my lack of understanding of lambdas and variable scopes, but I've been struggling with this problem for days, and could sure use some help!
Thanks!
class Vehiclestate_machine :initial => :parked doevent :ignite dotransition :parked => :idlingendevent :shift_up dotransition :idling => :first_gear, :first_gear => :second_gearendevent :restore dotransition :second_gear => :first_gear, :first_gear => :idling, :idling => :parkedendendend
class Vehicle < ActiveRecord::Basebefore_validation do |vehicle|# Set the actual value based on the previous state if we've just restoredvehicle.state = vehicle.previous_state if vehicle.restored?endstate_machine :initial => :parked doevent :ignite dotransition :parked => :idlingendevent :restore dotransition any => :restoredendstate :parked dovalidates_presence_of :nameendend# Look up previous state here...def previous_state'parked'endend
v = Vehicle.new(:name => 'test') # => #<Vehicle id: nil, name: "test", state: "parked">v.save # => truev.name = nil # => nilv.ignite # => truev # => #<Vehicle id: 1, name: nil, state: "idling">v.restore # => falsev.errors # => #<OrderedHash {:name=>["can't be blank"]}>v.state # => "idling"v.name = 'test' # => "test"v.restore # => truev # => #<Vehicle id: 1, name: "test", state: "parked">v.parked? # => true