benzelano / test_lh_import

1 stars 0 forks source link

Validations are not being run as per the documentation #66

Closed benzelano closed 13 years ago

benzelano commented 13 years ago

Greg Bolshaw opened this issue

Environment

I am using state_machine 0.9.4 with Ruby 1.9.2 and Rails 3.0.3.

Problem

Validations are being run for the wrong state

This is my model: class Foo < ActiveRecord::Base state_machine :initial => :step1 do event :next do transition :step1 => :step2 transition :step2 => :step3 end event :previous do transition :step3 => :step2 transition :step2 => :step1 end state :step1 do validates_presence_of :field1 end state :step2 do validates_presence_of :field2 end state :step3 do validates_presence_of :field3 end end
end

The documentation explains that validations will only run for the state that the object is currently in.

This is what I am finding:

> f = Foo.new
=> #<Foo id: nil, field1: nil, field2: nil, field3: nil, state: "step1", created_at: nil, updated_at: nil>
> f.next
=> false
> f.errors.full_messages 
=> ["Field2 can&rsquo;t be blank"]

Validations are not being run for the current state as expected, but for the state that is being transitioned to.

If I understand the documentation correctly, I expected :field1 to be validated at step1, :field2 at step2 and :field3 at step3.

original LH ticket

This ticket has 0 attachment(s).

benzelano commented 13 years ago

When a transition is made, the state is first changed on the record and then #save is called. As a result, state behaviors like "validates_presence_of" would run on the state being transitioned to.

In your case, I’d expect the state to represent the last step you’ve completed. In order to achieve what you’re looking for, you should define your state machine like so:

@@@ ruby class Foo < ActiveRecord::Base state_machine do event :next do transition nil => :step1, :step1 => :step2, :step2 => :step3 end event :previous do transition :step3 => :step2, :step2 => :step1, :step1 => nil end state :step1 do validates_presence_of :field1 end state :step2 do validates_presence_of :field2 end state :step3 do validates_presence_of :field3 end end
end @@@

Then, when you want to indicate that step1 is completed, you can call "next", which will set the state to "step1" and run the validations to ensure that all of the required fields for that step are complete.

Hope this helps.