pluginaweek / state_machine

Adds support for creating state machines for attributes on any Ruby class
http://www.pluginaweek.org
MIT License
3.74k stars 505 forks source link

Assigning 'state_event' through nested attributes fails. #327

Open smudge opened 9 years ago

smudge commented 9 years ago

It seems that this project is mostly dead/stalled at this point, but I'm filing this issue for posterity's sake.

The bug is around the ability to fire off an event by assigninment, as follows:

car.state_event = 'drive'
car.save! # fires off 'drive' event

Here's the repro setup (using a totally new rails 3.2.19 app):

class CreateWheels < ActiveRecord::Migration
  def change
    create_table :wheels do |t|
      t.references :car

      t.timestamps
    end
    add_index :wheels, :car_id
  end
end
class CreateCars < ActiveRecord::Migration
  def change
    create_table :cars do |t|
      t.string :state

      t.timestamps
    end
  end
end
class Car < ActiveRecord::Base
  attr_accessible :state_event

  state_machine :state, initial: :parked do
    event :drive do
      transition :parked => :driving
    end
    event :stop do
      transition :driving => :parked
    end
  end

end
class Wheel < ActiveRecord::Base
  belongs_to :car
  accepts_nested_attributes_for :car
  attr_accessible :car, :car_attributes
end

Then, from console (or in your controller) run the following commands:

Wheel.create!(car: Car.new)
w = Wheel.first
w.update_attributes(car_attributes: { state_event: :drive })
w = Wheel.first #reload that same wheel
w.update_attributes(car_attributes: { state_event: :stop })

That last command should cause the car to go from driving to parked, but instead the transaction is rolled back with the error :"car.state_event"=>["cannot transition when parked"]. If you check the car state without reloading the model, it says parked, but after reload it goes back to driving.

So it seems that something is setting the car state to parked as expected, but then a rollback occurs because the drive event cannot transition from a parked state. (Like it's trying to transition twice and then rolls it all back when the 2nd one fails.)