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 +4 -4
- data/lib/can_has_state/machine.rb +6 -6
- data/lib/can_has_state/version.rb +1 -1
- data/test/can_has_state_test.rb +68 -0
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 516a5676e62907d7868c5a0812c760e292b87c8c785cb246c5eb3bd2db2d7a41
|
4
|
+
data.tar.gz: 1e4b230a4a4c933b1db2884b2f7490439c9fb2f4f18b1ee686286decc2640903
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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
|
-
|
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
|
-
|
123
|
+
@can_has_state_errors[column] = [sm.message(to), {from: "'#{from}'", to: "'#{to}'"}]
|
124
124
|
end
|
125
125
|
end
|
126
|
-
|
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
|
data/test/can_has_state_test.rb
CHANGED
@@ -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|
|