can_has_state 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0b2d2008ba870961e06cebe22f027b133b46c5f078315938c9338edfd99678f5
4
- data.tar.gz: 2d4e7dbfd0bb896e01dfdaf66933b3b483f71915579f5d66d42fde1cbd0416de
3
+ metadata.gz: 516a5676e62907d7868c5a0812c760e292b87c8c785cb246c5eb3bd2db2d7a41
4
+ data.tar.gz: 1e4b230a4a4c933b1db2884b2f7490439c9fb2f4f18b1ee686286decc2640903
5
5
  SHA512:
6
- metadata.gz: 9e18bb675dd1acc0b84bb8539f67ca9c483f7ff618927b9baef5cdc738ba7a723cac0cccbaed68dfd0291925a2af5a8cda4ebf22b250ead0d39d813e389ecd86
7
- data.tar.gz: 2cc03d656532de9061758242d7daaab074f979665323a071d432b1c220e050951da7750ca6f38c5ef1c8e1e4633f76ce16bd8f404fbe9e5e31ba8fe0a6426f17
6
+ metadata.gz: cb9ef6c65385ef382a01d9f73c40da6217136f9939fea20eb6aae0183ce57f492e119302fc560f9273b2f6c2933cde3fa2c50daf3e0f13d038cf19dbfa377d5b
7
+ data.tar.gz: f1aee70c43b00b6ae153c63583db1d1bf4bd9adb072fa4b5adf33eecd1b4f3c1668aa1aba54438b296158ad858475a1d52333ce95f0e2e9959d1d1fb8b7d499b
@@ -111,23 +111,23 @@ module CanHasState
111
111
  end
112
112
  end
113
113
 
114
- def can_has_state_errors
115
- err = {}
114
+ def can_has_state_errors(reset: true)
115
+ @can_has_state_errors = {} if reset || !@can_has_state_errors
116
116
  state_machines.each do |column, sm|
117
117
  from, to = send("#{column}_was"), send(column)
118
118
  if !sm.known?(to)
119
- err[column] = [:invalid_state]
119
+ @can_has_state_errors[column] = [:invalid_state]
120
120
  elsif from == to
121
121
  next
122
122
  elsif !sm.allow?(self, to) #state_machine_allow?(column, to)
123
- err[column] = [sm.message(to), {from: "'#{from}'", to: "'#{to}'"}]
123
+ @can_has_state_errors[column] = [sm.message(to), {from: "'#{from}'", to: "'#{to}'"}]
124
124
  end
125
125
  end
126
- err
126
+ @can_has_state_errors
127
127
  end
128
128
 
129
129
  def validate_state_machines
130
- can_has_state_errors.each do |column, (msg, opts)|
130
+ can_has_state_errors(reset: false).each do |column, (msg, opts)|
131
131
  errors.add column, msg, **(opts||{})
132
132
  end
133
133
  end
@@ -1,3 +1,3 @@
1
1
  module CanHasState
2
- VERSION = '0.8.0'
2
+ VERSION = '0.9.0'
3
3
  end
@@ -406,6 +406,74 @@ class CanHasStateTest < Minitest::Test
406
406
  end
407
407
 
408
408
 
409
+ def test_errors_resolved_in_later_callback_are_kept
410
+ # Triggers are skipped when the state_machine has validation errors.
411
+ # Whether or not to skip is decided in an early before_validation callback.
412
+ # Even if a later callback resolves the validation error, it's important to
413
+ # still bubble up the errors since triggers did not run.
414
+ kl = build_from_skeleton do
415
+ attr_accessor :have_beans, :coffee_in_hand
416
+ extend_state_machine :state do
417
+ state :incredible,
418
+ require: proc{ coffee_in_hand > 0 }
419
+ end
420
+ before_validation { self.coffee_in_hand += 1 if have_beans }
421
+ def initialize
422
+ @coffee_in_hand = 0
423
+ end
424
+ end
425
+ m = kl.new
426
+ m.state = 'incredible'
427
+ refute m.valid?
428
+ assert m.errors.of_kind?(:state, :invalid_transition)
429
+ assert_equal 0, m.coffee_in_hand
430
+
431
+ m = kl.new
432
+ m.have_beans = true
433
+ m.state = 'incredible'
434
+ refute m.valid?
435
+ assert m.errors.of_kind?(:state, :invalid_transition)
436
+ assert_equal 1, m.coffee_in_hand
437
+ end
438
+
439
+ def test_rerunning_triggers_clears_pre_callback_errors
440
+ # To resolve the issue above, it is possible to re-eval the state_machine
441
+ # and run triggers if validations now pass. This is highly discouraged as
442
+ # complex callback callback interactions like this should be refactored out
443
+ # if at all possible.
444
+ # Not an officially supported solution and subject to change, but
445
+ # documented here to show that it is (presently) possible.
446
+ kl = build_from_skeleton do
447
+ attr_accessor :have_beans, :coffee_in_hand, :we_are_incredible
448
+ extend_state_machine :state do
449
+ state :incredible,
450
+ require: proc{ coffee_in_hand > 0 },
451
+ on_enter: proc{ self.we_are_incredible = true }
452
+ end
453
+ before_validation do
454
+ self.coffee_in_hand += 1 if have_beans
455
+ run_state_triggers
456
+ end
457
+ def initialize
458
+ @coffee_in_hand = 0
459
+ end
460
+ end
461
+ m = kl.new
462
+ m.state = 'incredible'
463
+ refute m.valid?
464
+ assert m.errors.of_kind?(:state, :invalid_transition)
465
+ assert_equal 0, m.coffee_in_hand
466
+ refute m.we_are_incredible
467
+
468
+ m = kl.new
469
+ m.have_beans = true
470
+ m.state = 'incredible'
471
+ assert m.valid?
472
+ assert_equal 1, m.coffee_in_hand
473
+ assert m.we_are_incredible
474
+ end
475
+
476
+
409
477
 
410
478
  def build_from_skeleton(&block)
411
479
  Class.new(Skeleton).tap do |kl|
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: can_has_state
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - thomas morgan