aasm: bang methods don't raise validation errors leading to hard to trace errors

First of all, thanks for doing aasm šŸ‘

When a validation error occurs only in a state that I transition to, the bang! method returns false, I stay in the old state and I have no idea why the transition failed.

What I would like to have is to have some sort of access to the error, or even better a configuration option that the bang! methods raise on validation errors. Maybe that exists and I just donā€™t know.

This way this was very hard to track down, why an object did not transition.

Now, taking this simple test class:

class AasmTest < ActiveRecord::Base
  include AASM

  validates :number, numericality: true, if: :failing?

  aasm column: 'state' do
    state :init, intial: true
    state :failing

    event :bam do
      transitions from: :init, to: :failing
    end
  end
end

And now take it for a spin:

[2] pry(main)> a = AasmTest.new
=> #<AasmTest:0x0000000c6fcac8 id: nil, state: nil, number: nil>
[3] pry(main)> a.valid?
=> true
[4] pry(main)> a.bam!
   (0.1ms)  BEGIN
   (0.1ms)  COMMIT
=> false
[5] pry(main)> a.valid?
=> true
[6] pry(main)> # I have no idea why it did not transition as it is valid, there is no guard etc.
[7] pry(main)> a.bam
   (0.1ms)  BEGIN
   (0.1ms)  COMMIT
=> true
[8] pry(main)> a.valid?
=> false
[9] pry(main)> a.errors
=> #<ActiveModel::Errors:0x0000000c2d9838 @base=#<AasmTest:0x0000000c6fcac8 id: nil, state: "failing", number: nil>, @messages={:number=>["ist keine Zahl"]}>
[10] pry(main)> a.save!
   (0.1ms)  BEGIN
   (0.1ms)  ROLLBACK
ActiveRecord::RecordInvalid: GĆ¼ltigkeitsprĆ¼fung ist fehlgeschlagen: Number ist keine Zahl
from /home/tobi/.rvm/gems/ruby-2.2.3@liefery-backend/gems/activerecord-4.2.3/lib/active_record/validations.rb:79:in `raise_record_invalid'
[11] pry(main)> # ah, that's why....

Thanks!

edit: I guess this somehow relates to #249 but Iā€™m asking for a different thing šŸ˜ƒ

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Reactions: 7
  • Comments: 18 (8 by maintainers)

Commits related to this issue

Most upvoted comments

I ended up using one of the provided callbacks to get the behavior that I wanted.

class MyModel < ActiveRecord::Base
  include AASM

  aasm do
    # state declarations and things
    ensure_on_all_events :raise_validation_errors
  end

  private

  def raise_validation_errors
    raise ActiveRecord::RecordInvalid.new(self) if errors.any?
  end
end

Wow, this one just bit me as well. I feel like the bang method of event transitions should never be able to silently return false. Would anyone ever want or expect the bang method to behave that way?

If anyone was interested I found workaround using aasm_event_failed, below is my implementation on an AR model class including aasm

def aasm_event_failed(event_name, new_state)
  if errors.any?
    raise ActiveRecord::RecordInvalid.new(self)
  end
end

PS: is it on purpose aasm_event_failed isnā€™t documented? Eg .I might get surprised itā€™s lost with next release;)

Thanks

@AlexVentura you need to explicitly set whiny_persistence to true when setting up the state machine in your model, else it just returns false instead of raising an exception, which is usually expected from bang methods.

šŸ‘ This one caught me unawares too recently. Had not researched it further yet.

Should not be hard to submit a pull request for this change.