aasm 4.2.0 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +4 -1
- data/Gemfile +2 -2
- data/PLANNED_CHANGES.md +24 -4
- data/README.md +75 -5
- data/lib/aasm/aasm.rb +50 -36
- data/lib/aasm/base.rb +36 -18
- data/lib/aasm/core/event.rb +6 -5
- data/lib/aasm/core/state.rb +3 -2
- data/lib/aasm/core/transition.rb +5 -4
- data/lib/aasm/errors.rb +7 -4
- data/lib/aasm/instance_base.rb +14 -13
- data/lib/aasm/localizer.rb +1 -1
- data/lib/aasm/persistence/active_record_persistence.rb +41 -66
- data/lib/aasm/persistence/base.rb +7 -7
- data/lib/aasm/persistence/mongo_mapper_persistence.rb +34 -51
- data/lib/aasm/persistence/mongoid_persistence.rb +15 -36
- data/lib/aasm/persistence/plain_persistence.rb +8 -7
- data/lib/aasm/persistence/sequel_persistence.rb +12 -10
- data/lib/aasm/state_machine.rb +11 -6
- data/lib/aasm/version.rb +1 -1
- data/spec/database.rb +27 -1
- data/spec/models/active_record/basic_active_record_two_state_machines_example.rb +25 -0
- data/spec/models/active_record/complex_active_record_example.rb +33 -0
- data/spec/models/active_record/derivate_new_dsl.rb +4 -0
- data/spec/models/active_record/false_state.rb +18 -0
- data/spec/models/active_record/gate.rb +20 -0
- data/spec/models/active_record/no_direct_assignment.rb +11 -0
- data/spec/models/active_record/no_scope.rb +11 -0
- data/spec/models/active_record/provided_and_persisted_state.rb +3 -3
- data/spec/models/active_record/simple_new_dsl.rb +9 -0
- data/spec/models/active_record/thief.rb +15 -0
- data/spec/models/active_record/with_enum.rb +20 -0
- data/spec/models/active_record/with_false_enum.rb +16 -0
- data/spec/models/active_record/with_true_enum.rb +20 -0
- data/spec/models/basic_two_state_machines_example.rb +25 -0
- data/spec/models/callbacks/basic_multiple.rb +75 -0
- data/spec/models/callbacks/guard_within_block_multiple.rb +66 -0
- data/spec/models/callbacks/multiple_transitions_transition_guard_multiple.rb +65 -0
- data/spec/models/callbacks/private_method_multiple.rb +44 -0
- data/spec/models/callbacks/with_args_multiple.rb +61 -0
- data/spec/models/callbacks/{with_state_args.rb → with_state_arg.rb} +0 -0
- data/spec/models/callbacks/with_state_arg_multiple.rb +26 -0
- data/spec/models/complex_example.rb +134 -0
- data/spec/models/conversation.rb +47 -1
- data/spec/models/foo.rb +57 -0
- data/spec/models/foo_callback_multiple.rb +45 -0
- data/spec/models/guardian_multiple.rb +48 -0
- data/spec/models/initial_state_proc.rb +16 -0
- data/spec/models/invalid_persistor.rb +15 -0
- data/spec/models/mongo_mapper/complex_mongo_mapper_example.rb +37 -0
- data/spec/models/mongo_mapper/no_scope_mongo_mapper.rb +11 -0
- data/spec/models/mongo_mapper/simple_mongo_mapper.rb +12 -0
- data/spec/models/mongo_mapper/simple_new_dsl_mongo_mapper.rb +13 -0
- data/spec/models/mongoid/complex_mongoid_example.rb +37 -0
- data/spec/models/mongoid/no_scope_mongoid.rb +11 -0
- data/spec/models/mongoid/simple_mongoid.rb +12 -0
- data/spec/models/mongoid/simple_new_dsl_mongoid.rb +13 -0
- data/spec/models/no_initial_state.rb +13 -0
- data/spec/models/parametrised_event.rb +1 -1
- data/spec/models/parametrised_event_multiple.rb +29 -0
- data/spec/models/provided_state.rb +3 -3
- data/spec/models/sequel/complex_sequel_example.rb +45 -0
- data/spec/models/sequel/sequel_multiple.rb +25 -0
- data/spec/models/sequel/sequel_simple.rb +25 -0
- data/spec/models/simple_multiple_example.rb +30 -0
- data/spec/models/sub_class.rb +4 -0
- data/spec/models/sub_class_with_more_states.rb +11 -0
- data/spec/models/super_class.rb +28 -0
- data/spec/models/transactor.rb +27 -0
- data/spec/models/valid_state_name.rb +12 -0
- data/spec/models/validator.rb +39 -0
- data/spec/unit/basic_two_state_machines_example_spec.rb +10 -0
- data/spec/unit/callback_multiple_spec.rb +295 -0
- data/spec/unit/callbacks_spec.rb +1 -1
- data/spec/unit/complex_multiple_example_spec.rb +99 -0
- data/spec/unit/edge_cases_spec.rb +16 -0
- data/spec/unit/event_multiple_spec.rb +73 -0
- data/spec/unit/event_spec.rb +11 -6
- data/spec/unit/guard_multiple_spec.rb +60 -0
- data/spec/unit/initial_state_multiple_spec.rb +15 -0
- data/spec/unit/inspection_multiple_spec.rb +201 -0
- data/spec/unit/persistence/active_record_persistence_multiple_spec.rb +560 -0
- data/spec/unit/persistence/active_record_persistence_spec.rb +17 -12
- data/spec/unit/persistence/mongo_mapper_persistence_multiple_spec.rb +146 -0
- data/spec/unit/persistence/{mongo_mapper_persistance_spec.rb → mongo_mapper_persistence_spec.rb} +7 -49
- data/spec/unit/persistence/mongoid_persistence_multiple_spec.rb +127 -0
- data/spec/unit/persistence/mongoid_persistence_spec.rb +79 -0
- data/spec/unit/persistence/sequel_persistence_multiple_spec.rb +153 -0
- data/spec/unit/persistence/sequel_persistence_spec.rb +7 -24
- data/spec/unit/reloading_spec.rb +1 -1
- data/spec/unit/simple_multiple_example_spec.rb +63 -0
- data/spec/unit/state_spec.rb +3 -1
- data/spec/unit/subclassing_multiple_spec.rb +39 -0
- data/spec/unit/transition_spec.rb +31 -22
- metadata +73 -9
- data/spec/unit/persistence/mongoid_persistance_spec.rb +0 -146
data/lib/aasm/core/state.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
module AASM::Core
|
2
2
|
class State
|
3
|
-
attr_reader :name, :options
|
3
|
+
attr_reader :name, :state_machine, :options
|
4
4
|
|
5
|
-
def initialize(name, klass, options={})
|
5
|
+
def initialize(name, klass, state_machine, options={})
|
6
6
|
@name = name
|
7
7
|
@klass = klass
|
8
|
+
@state_machine = state_machine
|
8
9
|
update(options)
|
9
10
|
end
|
10
11
|
|
data/lib/aasm/core/transition.rb
CHANGED
@@ -2,12 +2,13 @@ module AASM::Core
|
|
2
2
|
class Transition
|
3
3
|
include DslHelper
|
4
4
|
|
5
|
-
attr_reader :from, :to, :opts
|
5
|
+
attr_reader :from, :to, :event, :opts
|
6
6
|
alias_method :options, :opts
|
7
7
|
|
8
|
-
def initialize(opts, &block)
|
8
|
+
def initialize(event, opts, &block)
|
9
9
|
add_options_from_dsl(opts, [:on_transition, :guard, :after], &block) if block
|
10
10
|
|
11
|
+
@event = event
|
11
12
|
@from = opts[:from]
|
12
13
|
@to = opts[:to]
|
13
14
|
@guards = Array(opts[:guards]) + Array(opts[:guard]) + Array(opts[:if])
|
@@ -44,8 +45,8 @@ module AASM::Core
|
|
44
45
|
|
45
46
|
def invoke_callbacks_compatible_with_guard(code, record, args, options={})
|
46
47
|
if record.respond_to?(:aasm)
|
47
|
-
record.aasm.from_state = @from if record.aasm.respond_to?(:from_state=)
|
48
|
-
record.aasm.to_state = @to if record.aasm.respond_to?(:to_state=)
|
48
|
+
record.aasm(event.state_machine.name).from_state = @from if record.aasm(event.state_machine.name).respond_to?(:from_state=)
|
49
|
+
record.aasm(event.state_machine.name).to_state = @to if record.aasm(event.state_machine.name).respond_to?(:to_state=)
|
49
50
|
end
|
50
51
|
|
51
52
|
case code
|
data/lib/aasm/errors.rb
CHANGED
@@ -1,13 +1,16 @@
|
|
1
1
|
module AASM
|
2
2
|
|
3
|
+
class UnknownStateMachineError < RuntimeError; end
|
4
|
+
|
3
5
|
class InvalidTransition < RuntimeError
|
4
|
-
attr_reader :object, :event_name
|
5
|
-
|
6
|
-
|
6
|
+
attr_reader :object, :event_name, :state_machine_name
|
7
|
+
|
8
|
+
def initialize(object, event_name, state_machine_name)
|
9
|
+
@object, @event_name, @state_machine_name = object, event_name, state_machine_name
|
7
10
|
end
|
8
11
|
|
9
12
|
def message
|
10
|
-
"Event '#{event_name}' cannot transition from '#{object.aasm.current_state}'"
|
13
|
+
"Event '#{event_name}' cannot transition from '#{object.aasm(state_machine_name).current_state}'"
|
11
14
|
end
|
12
15
|
end
|
13
16
|
|
data/lib/aasm/instance_base.rb
CHANGED
@@ -3,21 +3,22 @@ module AASM
|
|
3
3
|
|
4
4
|
attr_accessor :from_state, :to_state, :current_event
|
5
5
|
|
6
|
-
def initialize(instance)
|
6
|
+
def initialize(instance, name=:default) # instance of the class including AASM, name of the state machine
|
7
7
|
@instance = instance
|
8
|
+
@name = name
|
8
9
|
end
|
9
10
|
|
10
11
|
def current_state
|
11
|
-
@instance.aasm_read_state
|
12
|
+
@instance.aasm_read_state(@name)
|
12
13
|
end
|
13
14
|
|
14
15
|
def current_state=(state)
|
15
|
-
@instance.aasm_write_state_without_persistence(state)
|
16
|
-
@current_state = state
|
16
|
+
@instance.aasm_write_state_without_persistence(state, @name)
|
17
|
+
# @current_state = state
|
17
18
|
end
|
18
19
|
|
19
20
|
def enter_initial_state
|
20
|
-
state_name = determine_state_name(@instance.class.aasm.initial_state)
|
21
|
+
state_name = determine_state_name(@instance.class.aasm(@name).initial_state)
|
21
22
|
state_object = state_object_for_name(state_name)
|
22
23
|
|
23
24
|
state_object.fire_callbacks(:before_enter, @instance)
|
@@ -29,24 +30,24 @@ module AASM
|
|
29
30
|
end
|
30
31
|
|
31
32
|
def human_state
|
32
|
-
AASM::Localizer.new.human_state_name(@instance.class, current_state)
|
33
|
+
AASM::Localizer.new.human_state_name(@instance.class, state_object_for_name(current_state))
|
33
34
|
end
|
34
35
|
|
35
36
|
def states(options={})
|
36
37
|
if options[:permitted]
|
37
38
|
# ugliness level 1000
|
38
39
|
permitted_event_names = events(:permitted => true).map(&:name)
|
39
|
-
transitions = @instance.class.aasm.state_machine.events.values_at(*permitted_event_names).compact.map {|e| e.transitions_from_state(current_state) }
|
40
|
+
transitions = @instance.class.aasm(@name).state_machine.events.values_at(*permitted_event_names).compact.map {|e| e.transitions_from_state(current_state) }
|
40
41
|
tos = transitions.map {|t| t[0] ? t[0].to : nil}.flatten.compact.map(&:to_sym).uniq
|
41
|
-
@instance.class.aasm.states.select {|s| tos.include?(s.name.to_sym)}
|
42
|
+
@instance.class.aasm(@name).states.select {|s| tos.include?(s.name.to_sym)}
|
42
43
|
else
|
43
|
-
@instance.class.aasm.states
|
44
|
+
@instance.class.aasm(@name).states
|
44
45
|
end
|
45
46
|
end
|
46
47
|
|
47
48
|
def events(options={})
|
48
49
|
state = options[:state] || current_state
|
49
|
-
events = @instance.class.aasm.events.select {|e| e.transitions_from_state?(state) }
|
50
|
+
events = @instance.class.aasm(@name).events.select {|e| e.transitions_from_state?(state) }
|
50
51
|
|
51
52
|
if options[:permitted]
|
52
53
|
# filters the results of events_for_current_state so that only those that
|
@@ -58,7 +59,7 @@ module AASM
|
|
58
59
|
end
|
59
60
|
|
60
61
|
def state_object_for_name(name)
|
61
|
-
obj = @instance.class.aasm.states.find {|s| s == name}
|
62
|
+
obj = @instance.class.aasm(@name).states.find {|s| s == name}
|
62
63
|
raise AASM::UndefinedState, "State :#{name} doesn't exist" if obj.nil?
|
63
64
|
obj
|
64
65
|
end
|
@@ -75,7 +76,7 @@ module AASM
|
|
75
76
|
end
|
76
77
|
|
77
78
|
def may_fire_event?(name, *args)
|
78
|
-
if event = @instance.class.aasm.state_machine.events[name]
|
79
|
+
if event = @instance.class.aasm(@name).state_machine.events[name]
|
79
80
|
!!event.may_fire?(@instance, *args)
|
80
81
|
else
|
81
82
|
false # unknown event
|
@@ -83,7 +84,7 @@ module AASM
|
|
83
84
|
end
|
84
85
|
|
85
86
|
def set_current_state_with_persistence(state)
|
86
|
-
save_success = @instance.aasm_write_state(state)
|
87
|
+
save_success = @instance.aasm_write_state(state, @name)
|
87
88
|
self.current_state = state if save_success
|
88
89
|
save_success
|
89
90
|
end
|
data/lib/aasm/localizer.rb
CHANGED
@@ -21,7 +21,7 @@ module AASM
|
|
21
21
|
|
22
22
|
def item_for(klass, state, ancestor, options={})
|
23
23
|
separator = options[:old_style] ? '.' : '/'
|
24
|
-
:"#{i18n_scope(klass)}.attributes.#{i18n_klass(ancestor)}.#{klass.aasm.attribute_name}#{separator}#{state}"
|
24
|
+
:"#{i18n_scope(klass)}.attributes.#{i18n_klass(ancestor)}.#{klass.aasm(state.state_machine.name).attribute_name}#{separator}#{state}"
|
25
25
|
end
|
26
26
|
|
27
27
|
def translate_queue(checklist)
|
@@ -30,7 +30,6 @@ module AASM
|
|
30
30
|
#
|
31
31
|
def self.included(base)
|
32
32
|
base.send(:include, AASM::Persistence::Base)
|
33
|
-
base.extend AASM::Persistence::ActiveRecordPersistence::ClassMethods
|
34
33
|
base.send(:include, AASM::Persistence::ActiveRecordPersistence::InstanceMethods)
|
35
34
|
|
36
35
|
base.after_initialize do
|
@@ -41,34 +40,6 @@ module AASM
|
|
41
40
|
base.validate :aasm_validate_states
|
42
41
|
end
|
43
42
|
|
44
|
-
module ClassMethods
|
45
|
-
|
46
|
-
def find_in_state(number, state, *args)
|
47
|
-
with_state_scope state do
|
48
|
-
find(number, *args)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def count_in_state(state, *args)
|
53
|
-
with_state_scope state do
|
54
|
-
count(*args)
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def calculate_in_state(state, *args)
|
59
|
-
with_state_scope state do
|
60
|
-
calculate(*args)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
protected
|
65
|
-
def with_state_scope(state)
|
66
|
-
with_scope :find => {:conditions => ["#{table_name}.#{aasm_column} = ?", state.to_s]} do
|
67
|
-
yield if block_given?
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
43
|
module InstanceMethods
|
73
44
|
|
74
45
|
# Writes <tt>state</tt> to the state column and persists it to the database
|
@@ -80,18 +51,18 @@ module AASM
|
|
80
51
|
# Foo.find(1).aasm.current_state # => :closed
|
81
52
|
#
|
82
53
|
# NOTE: intended to be called from an event
|
83
|
-
def aasm_write_state(state)
|
84
|
-
old_value = read_attribute(self.class.aasm.attribute_name)
|
85
|
-
aasm_write_attribute state
|
54
|
+
def aasm_write_state(state, name=:default)
|
55
|
+
old_value = read_attribute(self.class.aasm(name).attribute_name)
|
56
|
+
aasm_write_attribute state, name
|
86
57
|
|
87
|
-
success = if aasm_skipping_validations
|
88
|
-
value = aasm_raw_attribute_value
|
89
|
-
self.class.where(self.class.primary_key => self.id).update_all(self.class.aasm.attribute_name => value) == 1
|
58
|
+
success = if aasm_skipping_validations(name)
|
59
|
+
value = aasm_raw_attribute_value(state, name)
|
60
|
+
self.class.where(self.class.primary_key => self.id).update_all(self.class.aasm(name).attribute_name => value) == 1
|
90
61
|
else
|
91
62
|
self.save
|
92
63
|
end
|
93
64
|
unless success
|
94
|
-
write_attribute(self.class.aasm.attribute_name, old_value)
|
65
|
+
write_attribute(self.class.aasm(name).attribute_name, old_value)
|
95
66
|
return false
|
96
67
|
end
|
97
68
|
|
@@ -110,39 +81,39 @@ module AASM
|
|
110
81
|
# Foo.find(1).aasm.current_state # => :closed
|
111
82
|
#
|
112
83
|
# NOTE: intended to be called from an event
|
113
|
-
def aasm_write_state_without_persistence(state)
|
114
|
-
aasm_write_attribute
|
84
|
+
def aasm_write_state_without_persistence(state, name=:default)
|
85
|
+
aasm_write_attribute(state, name)
|
115
86
|
end
|
116
87
|
|
117
88
|
private
|
118
|
-
def aasm_enum
|
119
|
-
case AASM::StateMachine[self.class].config.enum
|
89
|
+
def aasm_enum(name=:default)
|
90
|
+
case AASM::StateMachine[self.class][name].config.enum
|
120
91
|
when false then nil
|
121
|
-
when true then aasm_guess_enum_method
|
122
|
-
when nil then aasm_guess_enum_method if aasm_column_looks_like_enum
|
123
|
-
else AASM::StateMachine[self.class].config.enum
|
92
|
+
when true then aasm_guess_enum_method(name)
|
93
|
+
when nil then aasm_guess_enum_method(name) if aasm_column_looks_like_enum(name)
|
94
|
+
else AASM::StateMachine[self.class][name].config.enum
|
124
95
|
end
|
125
96
|
end
|
126
97
|
|
127
|
-
def aasm_column_looks_like_enum
|
128
|
-
self.class.columns_hash[self.class.aasm.attribute_name.to_s].type == :integer
|
98
|
+
def aasm_column_looks_like_enum(name=:default)
|
99
|
+
self.class.columns_hash[self.class.aasm(name).attribute_name.to_s].type == :integer
|
129
100
|
end
|
130
101
|
|
131
|
-
def aasm_guess_enum_method
|
132
|
-
self.class.aasm.attribute_name.to_s.pluralize.to_sym
|
102
|
+
def aasm_guess_enum_method(name=:default)
|
103
|
+
self.class.aasm(name).attribute_name.to_s.pluralize.to_sym
|
133
104
|
end
|
134
105
|
|
135
|
-
def aasm_skipping_validations
|
136
|
-
AASM::StateMachine[self.class].config.skip_validation_on_save
|
106
|
+
def aasm_skipping_validations(state_machine_name)
|
107
|
+
AASM::StateMachine[self.class][state_machine_name].config.skip_validation_on_save
|
137
108
|
end
|
138
109
|
|
139
|
-
def aasm_write_attribute(state)
|
140
|
-
write_attribute
|
110
|
+
def aasm_write_attribute(state, name=:default)
|
111
|
+
write_attribute(self.class.aasm(name).attribute_name, aasm_raw_attribute_value(state, name))
|
141
112
|
end
|
142
113
|
|
143
|
-
def aasm_raw_attribute_value(state)
|
144
|
-
if aasm_enum
|
145
|
-
self.class.send(aasm_enum)[state]
|
114
|
+
def aasm_raw_attribute_value(state, name=:default)
|
115
|
+
if aasm_enum(name)
|
116
|
+
self.class.send(aasm_enum(name))[state]
|
146
117
|
else
|
147
118
|
state.to_s
|
148
119
|
end
|
@@ -164,32 +135,36 @@ module AASM
|
|
164
135
|
# foo.aasm_state # => nil
|
165
136
|
#
|
166
137
|
def aasm_ensure_initial_state
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
aasm.
|
138
|
+
AASM::StateMachine[self.class].keys.each do |state_machine_name|
|
139
|
+
# checking via respond_to? does not work in Rails <= 3
|
140
|
+
# if respond_to?(self.class.aasm(state_machine_name).attribute_name) && send(self.class.aasm(state_machine_name).attribute_name).blank? # Rails 4
|
141
|
+
if attribute_names.include?(self.class.aasm(state_machine_name).attribute_name.to_s) && send(self.class.aasm(state_machine_name).attribute_name).blank?
|
142
|
+
aasm(state_machine_name).enter_initial_state
|
143
|
+
end
|
171
144
|
end
|
172
145
|
end
|
173
146
|
|
174
|
-
def aasm_fire_event(name, options, *args, &block)
|
175
|
-
success = options[:persist] ? self.class.transaction(:requires_new => requires_new?) { super } : super
|
147
|
+
def aasm_fire_event(state_machine_name, name, options, *args, &block)
|
148
|
+
success = options[:persist] ? self.class.transaction(:requires_new => requires_new?(state_machine_name)) { super } : super
|
176
149
|
|
177
150
|
if success && options[:persist]
|
178
|
-
event = self.class.aasm.state_machine.events[name]
|
151
|
+
event = self.class.aasm(state_machine_name).state_machine.events[name]
|
179
152
|
event.fire_callbacks(:after_commit, self, *args)
|
180
153
|
end
|
181
154
|
|
182
155
|
success
|
183
156
|
end
|
184
157
|
|
185
|
-
def requires_new?
|
186
|
-
AASM::StateMachine[self.class].config.requires_new_transaction
|
158
|
+
def requires_new?(state_machine_name)
|
159
|
+
AASM::StateMachine[self.class][state_machine_name].config.requires_new_transaction
|
187
160
|
end
|
188
161
|
|
189
162
|
def aasm_validate_states
|
190
|
-
|
191
|
-
|
192
|
-
|
163
|
+
AASM::StateMachine[self.class].keys.each do |state_machine_name|
|
164
|
+
unless aasm_skipping_validations(state_machine_name)
|
165
|
+
if aasm(state_machine_name).current_state && !aasm(state_machine_name).states.include?(aasm(state_machine_name).current_state)
|
166
|
+
self.errors.add(AASM::StateMachine[self.class][state_machine_name].config.column , "is invalid")
|
167
|
+
end
|
193
168
|
end
|
194
169
|
end
|
195
170
|
end
|
@@ -32,10 +32,10 @@ module AASM
|
|
32
32
|
# NOTE: intended to be called from an event
|
33
33
|
#
|
34
34
|
# This allows for nil aasm states - be sure to add validation to your model
|
35
|
-
def aasm_read_state
|
36
|
-
state = send(self.class.aasm.attribute_name)
|
35
|
+
def aasm_read_state(name=:default)
|
36
|
+
state = send(self.class.aasm(name).attribute_name)
|
37
37
|
if new_record?
|
38
|
-
state.blank? ? aasm.determine_state_name(self.class.aasm.initial_state) : state.to_sym
|
38
|
+
state.blank? ? aasm(name).determine_state_name(self.class.aasm(name).initial_state) : state.to_sym
|
39
39
|
else
|
40
40
|
state.blank? ? nil : state.to_sym
|
41
41
|
end
|
@@ -55,10 +55,10 @@ module AASM
|
|
55
55
|
# make sure to create a (named) scope for each state
|
56
56
|
def state_with_scope(name, *args)
|
57
57
|
state_without_scope(name, *args)
|
58
|
-
if
|
58
|
+
if @state_machine.config.create_scopes && !@klass.respond_to?(name)
|
59
59
|
if @klass.ancestors.map {|klass| klass.to_s}.include?("ActiveRecord::Base")
|
60
60
|
|
61
|
-
conditions = {"#{@klass.table_name}.#{@klass.aasm.attribute_name}" => name.to_s}
|
61
|
+
conditions = {"#{@klass.table_name}.#{@klass.aasm(@name).attribute_name}" => name.to_s}
|
62
62
|
if ActiveRecord::VERSION::MAJOR >= 3
|
63
63
|
@klass.class_eval do
|
64
64
|
scope name, lambda { where(conditions) }
|
@@ -69,10 +69,10 @@ module AASM
|
|
69
69
|
end
|
70
70
|
end
|
71
71
|
elsif @klass.ancestors.map {|klass| klass.to_s}.include?("Mongoid::Document")
|
72
|
-
scope_options = lambda { @klass.send(:where, {@klass.aasm.attribute_name.to_sym => name.to_s}) }
|
72
|
+
scope_options = lambda { @klass.send(:where, {@klass.aasm(@name).attribute_name.to_sym => name.to_s}) }
|
73
73
|
@klass.send(:scope, name, scope_options)
|
74
74
|
elsif @klass.ancestors.map {|klass| klass.to_s}.include?("MongoMapper::Document")
|
75
|
-
conditions = { @klass.aasm.attribute_name.to_sym => name.to_s }
|
75
|
+
conditions = { @klass.aasm(@name).attribute_name.to_sym => name.to_s }
|
76
76
|
@klass.scope(name, lambda { @klass.where(conditions) })
|
77
77
|
end
|
78
78
|
end
|
@@ -32,7 +32,6 @@ module AASM
|
|
32
32
|
#
|
33
33
|
def self.included(base)
|
34
34
|
base.send(:include, AASM::Persistence::Base)
|
35
|
-
base.extend AASM::Persistence::MongoMapperPersistence::ClassMethods
|
36
35
|
base.send(:include, AASM::Persistence::MongoMapperPersistence::InstanceMethods)
|
37
36
|
|
38
37
|
base.before_create :aasm_ensure_initial_state
|
@@ -41,26 +40,6 @@ module AASM
|
|
41
40
|
base.validate :aasm_validate_states
|
42
41
|
end
|
43
42
|
|
44
|
-
module ClassMethods
|
45
|
-
|
46
|
-
def find_in_state(number, state, *args)
|
47
|
-
with_state_scope(state).find!(number, *args)
|
48
|
-
end
|
49
|
-
|
50
|
-
def count_in_state(state, *args)
|
51
|
-
with_state_scope(state).count(*args)
|
52
|
-
end
|
53
|
-
|
54
|
-
def calculate_in_state(state, *args)
|
55
|
-
with_state_scope(state).calculate(*args)
|
56
|
-
end
|
57
|
-
|
58
|
-
protected
|
59
|
-
def with_state_scope(state)
|
60
|
-
where(aasm.attribute_name.to_sym => state.to_s)
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
43
|
module InstanceMethods
|
65
44
|
|
66
45
|
# Writes <tt>state</tt> to the state column and persists it to the database
|
@@ -72,18 +51,18 @@ module AASM
|
|
72
51
|
# Foo.find(1).aasm.current_state # => :closed
|
73
52
|
#
|
74
53
|
# NOTE: intended to be called from an event
|
75
|
-
def aasm_write_state(state)
|
76
|
-
old_value = read_attribute(self.class.aasm.attribute_name)
|
77
|
-
|
54
|
+
def aasm_write_state(state, name=:default)
|
55
|
+
old_value = read_attribute(self.class.aasm(name).attribute_name)
|
56
|
+
write_attribute(self.class.aasm(name).attribute_name, state)
|
78
57
|
|
79
|
-
success = if aasm_skipping_validations
|
80
|
-
value = aasm_raw_attribute_value
|
81
|
-
self.class.where(self.class.primary_key => self.id).update_all(self.class.aasm.attribute_name => value) == 1
|
58
|
+
success = if aasm_skipping_validations(name)
|
59
|
+
value = aasm_raw_attribute_value(state, name)
|
60
|
+
self.class.where(self.class.primary_key => self.id).update_all(self.class.aasm(name).attribute_name => value) == 1
|
82
61
|
else
|
83
62
|
self.save
|
84
63
|
end
|
85
64
|
unless success
|
86
|
-
write_attribute(self.class.aasm.attribute_name, old_value)
|
65
|
+
write_attribute(self.class.aasm(name).attribute_name, old_value)
|
87
66
|
return false
|
88
67
|
end
|
89
68
|
|
@@ -102,39 +81,39 @@ module AASM
|
|
102
81
|
# Foo.find(1).aasm.current_state # => :closed
|
103
82
|
#
|
104
83
|
# NOTE: intended to be called from an event
|
105
|
-
def aasm_write_state_without_persistence(state)
|
106
|
-
aasm_write_attribute
|
84
|
+
def aasm_write_state_without_persistence(state, name=:default)
|
85
|
+
aasm_write_attribute(state, name)
|
107
86
|
end
|
108
87
|
|
109
88
|
private
|
110
|
-
def aasm_enum
|
111
|
-
case AASM::StateMachine[self.class].config.enum
|
89
|
+
def aasm_enum(name=:default)
|
90
|
+
case AASM::StateMachine[self.class][name].config.enum
|
112
91
|
when false then nil
|
113
|
-
when true then aasm_guess_enum_method
|
114
|
-
when nil then aasm_guess_enum_method if aasm_column_looks_like_enum
|
115
|
-
else AASM::StateMachine[self.class].config.enum
|
92
|
+
when true then aasm_guess_enum_method(name)
|
93
|
+
when nil then aasm_guess_enum_method(name) if aasm_column_looks_like_enum(name)
|
94
|
+
else AASM::StateMachine[self.class][name].config.enum
|
116
95
|
end
|
117
96
|
end
|
118
97
|
|
119
|
-
def aasm_column_looks_like_enum
|
120
|
-
self.class.keys[self.class.aasm.attribute_name.to_s].type == Integer
|
98
|
+
def aasm_column_looks_like_enum(name)
|
99
|
+
self.class.keys[self.class.aasm(name).attribute_name.to_s].type == Integer
|
121
100
|
end
|
122
101
|
|
123
|
-
def aasm_guess_enum_method
|
124
|
-
self.class.aasm.attribute_name.to_s.pluralize.to_sym
|
102
|
+
def aasm_guess_enum_method(name)
|
103
|
+
self.class.aasm(name).attribute_name.to_s.pluralize.to_sym
|
125
104
|
end
|
126
105
|
|
127
|
-
def aasm_skipping_validations
|
128
|
-
AASM::StateMachine[self.class].config.skip_validation_on_save
|
106
|
+
def aasm_skipping_validations(state_machine_name)
|
107
|
+
AASM::StateMachine[self.class][state_machine_name].config.skip_validation_on_save
|
129
108
|
end
|
130
109
|
|
131
|
-
def aasm_write_attribute(state)
|
132
|
-
write_attribute self.class.aasm.attribute_name, aasm_raw_attribute_value(state)
|
110
|
+
def aasm_write_attribute(state, name=:default)
|
111
|
+
write_attribute self.class.aasm(name).attribute_name, aasm_raw_attribute_value(state, name)
|
133
112
|
end
|
134
113
|
|
135
|
-
def aasm_raw_attribute_value(state)
|
136
|
-
if aasm_enum
|
137
|
-
self.class.send(aasm_enum)[state]
|
114
|
+
def aasm_raw_attribute_value(state, name=:default)
|
115
|
+
if aasm_enum(name)
|
116
|
+
self.class.send(aasm_enum(name))[state]
|
138
117
|
else
|
139
118
|
state.to_s
|
140
119
|
end
|
@@ -156,14 +135,18 @@ module AASM
|
|
156
135
|
# foo.aasm_state # => nil
|
157
136
|
#
|
158
137
|
def aasm_ensure_initial_state
|
159
|
-
|
138
|
+
AASM::StateMachine[self.class].keys.each do |state_machine_name|
|
139
|
+
send("#{self.class.aasm(state_machine_name).attribute_name}=", aasm(state_machine_name).enter_initial_state.to_s) if send(self.class.aasm(state_machine_name).attribute_name).blank?
|
140
|
+
end
|
160
141
|
end
|
161
142
|
|
162
143
|
def aasm_validate_states
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
144
|
+
AASM::StateMachine[self.class].keys.each do |state_machine_name|
|
145
|
+
send("#{self.class.aasm(state_machine_name).attribute_name}=", aasm(state_machine_name).enter_initial_state.to_s) if send(self.class.aasm(state_machine_name).attribute_name).blank?
|
146
|
+
unless AASM::StateMachine[self.class][state_machine_name].config.skip_validation_on_save
|
147
|
+
if aasm(state_machine_name).current_state && !aasm(state_machine_name).states.include?(aasm(state_machine_name).current_state)
|
148
|
+
self.errors.add(AASM::StateMachine[self.class][state_machine_name].config.column , "is invalid")
|
149
|
+
end
|
167
150
|
end
|
168
151
|
end
|
169
152
|
end
|