aasm 4.2.0 → 4.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (97) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +4 -1
  3. data/Gemfile +2 -2
  4. data/PLANNED_CHANGES.md +24 -4
  5. data/README.md +75 -5
  6. data/lib/aasm/aasm.rb +50 -36
  7. data/lib/aasm/base.rb +36 -18
  8. data/lib/aasm/core/event.rb +6 -5
  9. data/lib/aasm/core/state.rb +3 -2
  10. data/lib/aasm/core/transition.rb +5 -4
  11. data/lib/aasm/errors.rb +7 -4
  12. data/lib/aasm/instance_base.rb +14 -13
  13. data/lib/aasm/localizer.rb +1 -1
  14. data/lib/aasm/persistence/active_record_persistence.rb +41 -66
  15. data/lib/aasm/persistence/base.rb +7 -7
  16. data/lib/aasm/persistence/mongo_mapper_persistence.rb +34 -51
  17. data/lib/aasm/persistence/mongoid_persistence.rb +15 -36
  18. data/lib/aasm/persistence/plain_persistence.rb +8 -7
  19. data/lib/aasm/persistence/sequel_persistence.rb +12 -10
  20. data/lib/aasm/state_machine.rb +11 -6
  21. data/lib/aasm/version.rb +1 -1
  22. data/spec/database.rb +27 -1
  23. data/spec/models/active_record/basic_active_record_two_state_machines_example.rb +25 -0
  24. data/spec/models/active_record/complex_active_record_example.rb +33 -0
  25. data/spec/models/active_record/derivate_new_dsl.rb +4 -0
  26. data/spec/models/active_record/false_state.rb +18 -0
  27. data/spec/models/active_record/gate.rb +20 -0
  28. data/spec/models/active_record/no_direct_assignment.rb +11 -0
  29. data/spec/models/active_record/no_scope.rb +11 -0
  30. data/spec/models/active_record/provided_and_persisted_state.rb +3 -3
  31. data/spec/models/active_record/simple_new_dsl.rb +9 -0
  32. data/spec/models/active_record/thief.rb +15 -0
  33. data/spec/models/active_record/with_enum.rb +20 -0
  34. data/spec/models/active_record/with_false_enum.rb +16 -0
  35. data/spec/models/active_record/with_true_enum.rb +20 -0
  36. data/spec/models/basic_two_state_machines_example.rb +25 -0
  37. data/spec/models/callbacks/basic_multiple.rb +75 -0
  38. data/spec/models/callbacks/guard_within_block_multiple.rb +66 -0
  39. data/spec/models/callbacks/multiple_transitions_transition_guard_multiple.rb +65 -0
  40. data/spec/models/callbacks/private_method_multiple.rb +44 -0
  41. data/spec/models/callbacks/with_args_multiple.rb +61 -0
  42. data/spec/models/callbacks/{with_state_args.rb → with_state_arg.rb} +0 -0
  43. data/spec/models/callbacks/with_state_arg_multiple.rb +26 -0
  44. data/spec/models/complex_example.rb +134 -0
  45. data/spec/models/conversation.rb +47 -1
  46. data/spec/models/foo.rb +57 -0
  47. data/spec/models/foo_callback_multiple.rb +45 -0
  48. data/spec/models/guardian_multiple.rb +48 -0
  49. data/spec/models/initial_state_proc.rb +16 -0
  50. data/spec/models/invalid_persistor.rb +15 -0
  51. data/spec/models/mongo_mapper/complex_mongo_mapper_example.rb +37 -0
  52. data/spec/models/mongo_mapper/no_scope_mongo_mapper.rb +11 -0
  53. data/spec/models/mongo_mapper/simple_mongo_mapper.rb +12 -0
  54. data/spec/models/mongo_mapper/simple_new_dsl_mongo_mapper.rb +13 -0
  55. data/spec/models/mongoid/complex_mongoid_example.rb +37 -0
  56. data/spec/models/mongoid/no_scope_mongoid.rb +11 -0
  57. data/spec/models/mongoid/simple_mongoid.rb +12 -0
  58. data/spec/models/mongoid/simple_new_dsl_mongoid.rb +13 -0
  59. data/spec/models/no_initial_state.rb +13 -0
  60. data/spec/models/parametrised_event.rb +1 -1
  61. data/spec/models/parametrised_event_multiple.rb +29 -0
  62. data/spec/models/provided_state.rb +3 -3
  63. data/spec/models/sequel/complex_sequel_example.rb +45 -0
  64. data/spec/models/sequel/sequel_multiple.rb +25 -0
  65. data/spec/models/sequel/sequel_simple.rb +25 -0
  66. data/spec/models/simple_multiple_example.rb +30 -0
  67. data/spec/models/sub_class.rb +4 -0
  68. data/spec/models/sub_class_with_more_states.rb +11 -0
  69. data/spec/models/super_class.rb +28 -0
  70. data/spec/models/transactor.rb +27 -0
  71. data/spec/models/valid_state_name.rb +12 -0
  72. data/spec/models/validator.rb +39 -0
  73. data/spec/unit/basic_two_state_machines_example_spec.rb +10 -0
  74. data/spec/unit/callback_multiple_spec.rb +295 -0
  75. data/spec/unit/callbacks_spec.rb +1 -1
  76. data/spec/unit/complex_multiple_example_spec.rb +99 -0
  77. data/spec/unit/edge_cases_spec.rb +16 -0
  78. data/spec/unit/event_multiple_spec.rb +73 -0
  79. data/spec/unit/event_spec.rb +11 -6
  80. data/spec/unit/guard_multiple_spec.rb +60 -0
  81. data/spec/unit/initial_state_multiple_spec.rb +15 -0
  82. data/spec/unit/inspection_multiple_spec.rb +201 -0
  83. data/spec/unit/persistence/active_record_persistence_multiple_spec.rb +560 -0
  84. data/spec/unit/persistence/active_record_persistence_spec.rb +17 -12
  85. data/spec/unit/persistence/mongo_mapper_persistence_multiple_spec.rb +146 -0
  86. data/spec/unit/persistence/{mongo_mapper_persistance_spec.rb → mongo_mapper_persistence_spec.rb} +7 -49
  87. data/spec/unit/persistence/mongoid_persistence_multiple_spec.rb +127 -0
  88. data/spec/unit/persistence/mongoid_persistence_spec.rb +79 -0
  89. data/spec/unit/persistence/sequel_persistence_multiple_spec.rb +153 -0
  90. data/spec/unit/persistence/sequel_persistence_spec.rb +7 -24
  91. data/spec/unit/reloading_spec.rb +1 -1
  92. data/spec/unit/simple_multiple_example_spec.rb +63 -0
  93. data/spec/unit/state_spec.rb +3 -1
  94. data/spec/unit/subclassing_multiple_spec.rb +39 -0
  95. data/spec/unit/transition_spec.rb +31 -22
  96. metadata +73 -9
  97. data/spec/unit/persistence/mongoid_persistance_spec.rb +0 -146
@@ -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
 
@@ -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
@@ -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
- def initialize(object, event_name)
6
- @object, @event_name = object, event_name
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
 
@@ -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
@@ -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 state
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 state
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 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))
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
- # checking via respond_to? does not work in Rails <= 3
168
- # if respond_to?(self.class.aasm.attribute_name) && send(self.class.aasm.attribute_name).blank? # Rails 4
169
- if attribute_names.include?(self.class.aasm.attribute_name.to_s) && send(self.class.aasm.attribute_name).blank?
170
- aasm.enter_initial_state
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
- unless aasm_skipping_validations
191
- if aasm.current_state && !aasm.states.include?(aasm.current_state)
192
- self.errors.add(AASM::StateMachine[self.class].config.column , "is invalid")
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 AASM::StateMachine[@klass].config.create_scopes && !@klass.respond_to?(name)
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
- aasm_write_attribute state
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 state
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 state
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
- return send("#{self.class.aasm.attribute_name}=", aasm.enter_initial_state.to_s) if send(self.class.aasm.attribute_name).blank?
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
- send("#{self.class.aasm.attribute_name}=", aasm.enter_initial_state.to_s) if send(self.class.aasm.attribute_name).blank?
164
- unless AASM::StateMachine[self.class].config.skip_validation_on_save
165
- if aasm.current_state && !aasm.states.include?(aasm.current_state)
166
- self.errors.add(AASM::StateMachine[self.class].config.column , "is invalid")
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