aasm 4.2.0 → 4.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|