State_machine also provided an alternative solution here: https://groups.google.com/d/msg/pluginaweek-talk/LL9VJdL_x9c/vP1qv6br734J
In particular:
Another possible solution is to be a little creative in how the state machine works. There are many hooks in ORMs such as ActiveRecord that give us the ability to set state at any stage of the process. Consider the following:
class Vehicle < ActiveRecord::Base before_validation do |vehicle|
This example introduces a new state that has been restored, although it is never stored in the database. Instead, we provide a before_validation hook that overwrites the state based on the previous state. You can see the results below:
v = Vehicle.new(:name => 'test') # => #<Vehicle id: nil, name: "test", state: "parked"> v.save # => true v.name = nil # => nil v.ignite # => true v # => #<Vehicle id: 1, name: nil, state: "idling"> v.restore # => false v.errors # => #<OrderedHash {:name=>["can't be blank"]}> v.state # => "idling" v.name = 'test' # => "test" v.restore # => true v # => #<Vehicle id: 1, name: "test", state: "parked"> v.parked? # => true
This should require more than one hit of the database, as happens before validation. In my case, the full picture looks like this:
module Interpreting::Status extend ActiveSupport::Concern included do before_validation :restore_previous_state, if: :interpreter_cancelled? state_machine :state, :initial => :ordered do before_transition :to => :interpreter_booked, :do => :set_previous_state state :ordered state :confirmed state :interpreter_booked state :interpreter_cancelled
source share