aasm 4.12.3 → 5.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/README.md +284 -119
- data/lib/aasm/aasm.rb +30 -27
- data/lib/aasm/base.rb +61 -11
- data/lib/aasm/configuration.rb +3 -0
- data/lib/aasm/core/event.rb +26 -30
- data/lib/aasm/core/invoker.rb +129 -0
- data/lib/aasm/core/invokers/base_invoker.rb +75 -0
- data/lib/aasm/core/invokers/class_invoker.rb +52 -0
- data/lib/aasm/core/invokers/literal_invoker.rb +49 -0
- data/lib/aasm/core/invokers/proc_invoker.rb +59 -0
- data/lib/aasm/core/state.rb +16 -14
- data/lib/aasm/core/transition.rb +8 -69
- data/lib/aasm/dsl_helper.rb +24 -22
- data/lib/aasm/errors.rb +5 -3
- data/lib/aasm/instance_base.rb +28 -5
- data/lib/aasm/localizer.rb +13 -3
- data/lib/aasm/persistence/active_record_persistence.rb +25 -5
- data/lib/aasm/persistence/base.rb +14 -3
- data/lib/aasm/persistence/core_data_query_persistence.rb +2 -1
- data/lib/aasm/persistence/dynamoid_persistence.rb +1 -1
- data/lib/aasm/persistence/mongoid_persistence.rb +1 -1
- data/lib/aasm/persistence/no_brainer_persistence.rb +105 -0
- data/lib/aasm/persistence/orm.rb +23 -19
- data/lib/aasm/persistence/plain_persistence.rb +2 -1
- data/lib/aasm/persistence/redis_persistence.rb +1 -1
- data/lib/aasm/persistence/sequel_persistence.rb +0 -1
- data/lib/aasm/persistence.rb +3 -0
- data/lib/aasm/rspec/allow_event.rb +5 -1
- data/lib/aasm/rspec/allow_transition_to.rb +5 -1
- data/lib/aasm/rspec/transition_from.rb +5 -1
- data/lib/aasm/version.rb +1 -1
- data/lib/aasm.rb +5 -2
- data/lib/generators/aasm/orm_helpers.rb +7 -1
- data/lib/generators/active_record/aasm_generator.rb +3 -1
- data/lib/generators/active_record/templates/migration.rb +1 -1
- data/lib/generators/nobrainer/aasm_generator.rb +28 -0
- data/lib/motion-aasm.rb +1 -0
- metadata +42 -344
- data/.document +0 -6
- data/.gitignore +0 -20
- data/.travis.yml +0 -52
- data/API +0 -34
- data/Appraisals +0 -43
- data/CHANGELOG.md +0 -370
- data/CODE_OF_CONDUCT.md +0 -13
- data/CONTRIBUTING.md +0 -24
- data/Gemfile +0 -7
- data/Gemfile.lock_old +0 -151
- data/HOWTO +0 -12
- data/PLANNED_CHANGES.md +0 -11
- data/README_FROM_VERSION_3_TO_4.md +0 -240
- data/Rakefile +0 -31
- data/TESTING.md +0 -25
- data/aasm.gemspec +0 -35
- data/callbacks.txt +0 -51
- data/gemfiles/rails_3.2.gemfile +0 -13
- data/gemfiles/rails_4.0.gemfile +0 -15
- data/gemfiles/rails_4.2.gemfile +0 -16
- data/gemfiles/rails_4.2_mongoid_5.gemfile +0 -11
- data/gemfiles/rails_5.0.gemfile +0 -14
- data/spec/database.rb +0 -44
- data/spec/database.yml +0 -3
- data/spec/en.yml +0 -12
- data/spec/en_deprecated_style.yml +0 -10
- data/spec/generators/active_record_generator_spec.rb +0 -47
- data/spec/generators/mongoid_generator_spec.rb +0 -31
- data/spec/models/active_record/basic_active_record_two_state_machines_example.rb +0 -25
- data/spec/models/active_record/complex_active_record_example.rb +0 -37
- data/spec/models/active_record/derivate_new_dsl.rb +0 -7
- data/spec/models/active_record/false_state.rb +0 -35
- data/spec/models/active_record/gate.rb +0 -39
- data/spec/models/active_record/invalid_persistor.rb +0 -29
- data/spec/models/active_record/localizer_test_model.rb +0 -34
- data/spec/models/active_record/no_direct_assignment.rb +0 -21
- data/spec/models/active_record/no_scope.rb +0 -21
- data/spec/models/active_record/persisted_state.rb +0 -12
- data/spec/models/active_record/provided_and_persisted_state.rb +0 -24
- data/spec/models/active_record/reader.rb +0 -7
- data/spec/models/active_record/readme_job.rb +0 -21
- data/spec/models/active_record/silent_persistor.rb +0 -29
- data/spec/models/active_record/simple_new_dsl.rb +0 -17
- data/spec/models/active_record/thief.rb +0 -29
- data/spec/models/active_record/transactor.rb +0 -124
- data/spec/models/active_record/transient.rb +0 -6
- data/spec/models/active_record/validator.rb +0 -118
- data/spec/models/active_record/with_enum.rb +0 -39
- data/spec/models/active_record/with_enum_without_column.rb +0 -38
- data/spec/models/active_record/with_false_enum.rb +0 -31
- data/spec/models/active_record/with_true_enum.rb +0 -39
- data/spec/models/active_record/worker.rb +0 -2
- data/spec/models/active_record/writer.rb +0 -6
- data/spec/models/basic_two_state_machines_example.rb +0 -25
- data/spec/models/callbacks/basic.rb +0 -98
- data/spec/models/callbacks/basic_multiple.rb +0 -75
- data/spec/models/callbacks/guard_within_block.rb +0 -67
- data/spec/models/callbacks/guard_within_block_multiple.rb +0 -66
- data/spec/models/callbacks/multiple_transitions_transition_guard.rb +0 -66
- data/spec/models/callbacks/multiple_transitions_transition_guard_multiple.rb +0 -65
- data/spec/models/callbacks/private_method.rb +0 -44
- data/spec/models/callbacks/private_method_multiple.rb +0 -44
- data/spec/models/callbacks/with_args.rb +0 -62
- data/spec/models/callbacks/with_args_multiple.rb +0 -61
- data/spec/models/callbacks/with_state_arg.rb +0 -30
- data/spec/models/callbacks/with_state_arg_multiple.rb +0 -26
- data/spec/models/complex_example.rb +0 -222
- data/spec/models/conversation.rb +0 -93
- data/spec/models/default_state.rb +0 -12
- data/spec/models/double_definer.rb +0 -21
- data/spec/models/dynamoid/complex_dynamoid_example.rb +0 -37
- data/spec/models/dynamoid/dynamoid_multiple.rb +0 -18
- data/spec/models/dynamoid/dynamoid_simple.rb +0 -18
- data/spec/models/foo.rb +0 -106
- data/spec/models/foo_callback_multiple.rb +0 -45
- data/spec/models/guard_arguments_check.rb +0 -17
- data/spec/models/guard_with_params.rb +0 -24
- data/spec/models/guard_with_params_multiple.rb +0 -18
- data/spec/models/guardian.rb +0 -58
- data/spec/models/guardian_multiple.rb +0 -48
- data/spec/models/guardian_without_from_specified.rb +0 -18
- data/spec/models/initial_state_proc.rb +0 -31
- data/spec/models/mongoid/complex_mongoid_example.rb +0 -37
- data/spec/models/mongoid/invalid_persistor_mongoid.rb +0 -39
- data/spec/models/mongoid/mongoid_relationships.rb +0 -26
- data/spec/models/mongoid/no_scope_mongoid.rb +0 -21
- data/spec/models/mongoid/silent_persistor_mongoid.rb +0 -39
- data/spec/models/mongoid/simple_mongoid.rb +0 -23
- data/spec/models/mongoid/simple_new_dsl_mongoid.rb +0 -25
- data/spec/models/mongoid/validator_mongoid.rb +0 -100
- data/spec/models/multi_transitioner.rb +0 -34
- data/spec/models/multiple_transitions_that_differ_only_by_guard.rb +0 -31
- data/spec/models/namespaced_multiple_example.rb +0 -42
- data/spec/models/no_initial_state.rb +0 -25
- data/spec/models/not_auto_loaded/process.rb +0 -21
- data/spec/models/parametrised_event.rb +0 -42
- data/spec/models/parametrised_event_multiple.rb +0 -29
- data/spec/models/process_with_new_dsl.rb +0 -31
- data/spec/models/provided_state.rb +0 -24
- data/spec/models/redis/complex_redis_example.rb +0 -40
- data/spec/models/redis/redis_multiple.rb +0 -20
- data/spec/models/redis/redis_simple.rb +0 -20
- data/spec/models/sequel/complex_sequel_example.rb +0 -46
- data/spec/models/sequel/invalid_persistor.rb +0 -52
- data/spec/models/sequel/sequel_multiple.rb +0 -25
- data/spec/models/sequel/sequel_simple.rb +0 -26
- data/spec/models/sequel/silent_persistor.rb +0 -50
- data/spec/models/sequel/transactor.rb +0 -112
- data/spec/models/sequel/validator.rb +0 -93
- data/spec/models/sequel/worker.rb +0 -12
- data/spec/models/silencer.rb +0 -27
- data/spec/models/simple_custom_example.rb +0 -53
- data/spec/models/simple_example.rb +0 -15
- data/spec/models/simple_multiple_example.rb +0 -42
- data/spec/models/state_machine_with_failed_event.rb +0 -20
- data/spec/models/states_on_one_line_example.rb +0 -8
- data/spec/models/sub_class.rb +0 -41
- data/spec/models/sub_class_with_more_states.rb +0 -18
- data/spec/models/sub_classing.rb +0 -3
- data/spec/models/super_class.rb +0 -46
- data/spec/models/this_name_better_not_be_in_use.rb +0 -11
- data/spec/models/valid_state_name.rb +0 -23
- data/spec/spec_helper.rb +0 -26
- data/spec/spec_helpers/active_record.rb +0 -7
- data/spec/spec_helpers/dynamoid.rb +0 -33
- data/spec/spec_helpers/mongoid.rb +0 -7
- data/spec/spec_helpers/redis.rb +0 -15
- data/spec/spec_helpers/remove_warnings.rb +0 -1
- data/spec/spec_helpers/sequel.rb +0 -7
- data/spec/unit/api_spec.rb +0 -100
- data/spec/unit/basic_two_state_machines_example_spec.rb +0 -10
- data/spec/unit/callback_multiple_spec.rb +0 -300
- data/spec/unit/callbacks_spec.rb +0 -491
- data/spec/unit/complex_example_spec.rb +0 -94
- data/spec/unit/complex_multiple_example_spec.rb +0 -115
- data/spec/unit/edge_cases_spec.rb +0 -16
- data/spec/unit/event_multiple_spec.rb +0 -73
- data/spec/unit/event_naming_spec.rb +0 -16
- data/spec/unit/event_spec.rb +0 -381
- data/spec/unit/exception_spec.rb +0 -11
- data/spec/unit/guard_arguments_check_spec.rb +0 -9
- data/spec/unit/guard_multiple_spec.rb +0 -60
- data/spec/unit/guard_spec.rb +0 -89
- data/spec/unit/guard_with_params_multiple_spec.rb +0 -10
- data/spec/unit/guard_with_params_spec.rb +0 -14
- data/spec/unit/guard_without_from_specified_spec.rb +0 -10
- data/spec/unit/initial_state_multiple_spec.rb +0 -15
- data/spec/unit/initial_state_spec.rb +0 -12
- data/spec/unit/inspection_multiple_spec.rb +0 -201
- data/spec/unit/inspection_spec.rb +0 -149
- data/spec/unit/localizer_spec.rb +0 -78
- data/spec/unit/memory_leak_spec.rb +0 -38
- data/spec/unit/multiple_transitions_that_differ_only_by_guard_spec.rb +0 -14
- data/spec/unit/namespaced_multiple_example_spec.rb +0 -75
- data/spec/unit/new_dsl_spec.rb +0 -12
- data/spec/unit/override_warning_spec.rb +0 -94
- data/spec/unit/persistence/active_record_persistence_multiple_spec.rb +0 -618
- data/spec/unit/persistence/active_record_persistence_spec.rb +0 -735
- data/spec/unit/persistence/dynamoid_persistence_multiple_spec.rb +0 -135
- data/spec/unit/persistence/dynamoid_persistence_spec.rb +0 -84
- data/spec/unit/persistence/mongoid_persistence_multiple_spec.rb +0 -204
- data/spec/unit/persistence/mongoid_persistence_spec.rb +0 -169
- data/spec/unit/persistence/redis_persistence_multiple_spec.rb +0 -88
- data/spec/unit/persistence/redis_persistence_spec.rb +0 -53
- data/spec/unit/persistence/sequel_persistence_multiple_spec.rb +0 -148
- data/spec/unit/persistence/sequel_persistence_spec.rb +0 -368
- data/spec/unit/readme_spec.rb +0 -41
- data/spec/unit/reloading_spec.rb +0 -15
- data/spec/unit/rspec_matcher_spec.rb +0 -79
- data/spec/unit/simple_custom_example_spec.rb +0 -39
- data/spec/unit/simple_example_spec.rb +0 -42
- data/spec/unit/simple_multiple_example_spec.rb +0 -91
- data/spec/unit/state_spec.rb +0 -89
- data/spec/unit/states_on_one_line_example_spec.rb +0 -16
- data/spec/unit/subclassing_multiple_spec.rb +0 -74
- data/spec/unit/subclassing_spec.rb +0 -46
- data/spec/unit/transition_spec.rb +0 -436
- data/test/minitest_helper.rb +0 -57
- data/test/unit/minitest_matcher_test.rb +0 -80
data/README.md
CHANGED
@@ -2,8 +2,8 @@
|
|
2
2
|
|
3
3
|
[![Gem Version](https://badge.fury.io/rb/aasm.svg)](http://badge.fury.io/rb/aasm)
|
4
4
|
[![Build Status](https://travis-ci.org/aasm/aasm.svg?branch=master)](https://travis-ci.org/aasm/aasm)
|
5
|
-
[![Dependency Status](https://gemnasium.com/aasm/aasm.svg)](https://gemnasium.com/aasm/aasm)
|
6
5
|
[![Code Climate](https://codeclimate.com/github/aasm/aasm/badges/gpa.svg)](https://codeclimate.com/github/aasm/aasm)
|
6
|
+
[![codecov](https://codecov.io/gh/aasm/aasm/branch/master/graph/badge.svg)](https://codecov.io/gh/aasm/aasm)
|
7
7
|
|
8
8
|
## Index
|
9
9
|
- [Upgrade from version 3 to 4](#upgrade-from-version-3-to-4)
|
@@ -20,15 +20,18 @@
|
|
20
20
|
- [Extending AASM](#extending-aasm)
|
21
21
|
- [ActiveRecord](#activerecord)
|
22
22
|
- [Bang events](#bang-events)
|
23
|
+
- [Timestamps](#timestamps)
|
23
24
|
- [ActiveRecord enums](#activerecord-enums)
|
24
25
|
- [Sequel](#sequel)
|
25
26
|
- [Dynamoid](#dynamoid)
|
26
27
|
- [Mongoid](#mongoid)
|
28
|
+
- [Nobrainer](#nobrainer)
|
27
29
|
- [Redis](#redis)
|
28
30
|
- [Automatic Scopes](#automatic-scopes)
|
29
31
|
- [Transaction support](#transaction-support)
|
30
32
|
- [Pessimistic Locking](#pessimistic-locking)
|
31
33
|
- [Column name & migration](#column-name--migration)
|
34
|
+
- [Log State Changes](#log-state-changes)
|
32
35
|
- [Inspection](#inspection)
|
33
36
|
- [Warning output](#warning-output)
|
34
37
|
- [RubyMotion support](#rubymotion-support)
|
@@ -42,6 +45,7 @@
|
|
42
45
|
- [Bundler](#or-if-you-are-using-bundler)
|
43
46
|
- [Building your own gems](#building-your-own-gems)
|
44
47
|
- [Generators](#generators)
|
48
|
+
- [Test suite with Docker](#docker)
|
45
49
|
- [Latest changes](#latest-changes)
|
46
50
|
- [Questions?](#questions)
|
47
51
|
- [Maintainers](#maintainers)
|
@@ -52,10 +56,8 @@
|
|
52
56
|
This package contains AASM, a library for adding finite state machines to Ruby classes.
|
53
57
|
|
54
58
|
AASM started as the *acts_as_state_machine* plugin but has evolved into a more generic library
|
55
|
-
that no longer targets only ActiveRecord models. It currently provides adapters for
|
56
|
-
|
57
|
-
and [Mongoid](http://mongoid.org/) but it can be used for any Ruby class, no matter what
|
58
|
-
parent class it has (if any).
|
59
|
+
that no longer targets only ActiveRecord models. It currently provides adapters for many
|
60
|
+
ORMs but it can be used for any Ruby class, no matter what parent class it has (if any).
|
59
61
|
|
60
62
|
## Upgrade from version 3 to 4
|
61
63
|
|
@@ -71,19 +73,19 @@ class Job
|
|
71
73
|
include AASM
|
72
74
|
|
73
75
|
aasm do
|
74
|
-
state :sleeping, :
|
76
|
+
state :sleeping, initial: true
|
75
77
|
state :running, :cleaning
|
76
78
|
|
77
79
|
event :run do
|
78
|
-
transitions :
|
80
|
+
transitions from: :sleeping, to: :running
|
79
81
|
end
|
80
82
|
|
81
83
|
event :clean do
|
82
|
-
transitions :
|
84
|
+
transitions from: :running, to: :cleaning
|
83
85
|
end
|
84
86
|
|
85
87
|
event :sleep do
|
86
|
-
transitions :
|
88
|
+
transitions from: [:running, :cleaning], to: :sleeping
|
87
89
|
end
|
88
90
|
end
|
89
91
|
|
@@ -109,7 +111,7 @@ AASM not to be *whiny*:
|
|
109
111
|
```ruby
|
110
112
|
class Job
|
111
113
|
...
|
112
|
-
aasm :
|
114
|
+
aasm whiny_transitions: false do
|
113
115
|
...
|
114
116
|
end
|
115
117
|
end
|
@@ -130,27 +132,27 @@ the transition succeeds :
|
|
130
132
|
|
131
133
|
### Callbacks
|
132
134
|
|
133
|
-
You can define a number of callbacks for your transitions. These methods will be
|
134
|
-
called
|
135
|
+
You can define a number of callbacks for your events, transitions and states. These methods, Procs or classes will be
|
136
|
+
called when certain criteria are met, like entering a particular state:
|
135
137
|
|
136
138
|
```ruby
|
137
139
|
class Job
|
138
140
|
include AASM
|
139
141
|
|
140
142
|
aasm do
|
141
|
-
state :sleeping, :
|
142
|
-
state :running
|
143
|
+
state :sleeping, initial: true, before_enter: :do_something
|
144
|
+
state :running, before_enter: Proc.new { do_something && notify_somebody }
|
143
145
|
state :finished
|
144
146
|
|
145
147
|
after_all_transitions :log_status_change
|
146
148
|
|
147
|
-
event :run, :
|
149
|
+
event :run, after: :notify_somebody do
|
148
150
|
before do
|
149
151
|
log('Preparing to run')
|
150
152
|
end
|
151
153
|
|
152
|
-
transitions :
|
153
|
-
transitions :
|
154
|
+
transitions from: :sleeping, to: :running, after: Proc.new {|*args| set_process(*args) }
|
155
|
+
transitions from: :running, to: :finished, after: LogRunTime
|
154
156
|
end
|
155
157
|
|
156
158
|
event :sleep do
|
@@ -160,7 +162,7 @@ class Job
|
|
160
162
|
error do |e|
|
161
163
|
...
|
162
164
|
end
|
163
|
-
transitions :
|
165
|
+
transitions from: :running, to: :sleeping
|
164
166
|
end
|
165
167
|
end
|
166
168
|
|
@@ -195,6 +197,8 @@ is finished.
|
|
195
197
|
|
196
198
|
AASM will also initialize `LogRunTime` and run the `call` method for you after the transition from `running` to `finished` in the example above. You can pass arguments to the class by defining an initialize method on it, like this:
|
197
199
|
|
200
|
+
Note that Procs are executed in the context of a record, it means that you don't need to expect the record as an argument, just call the methods you need.
|
201
|
+
|
198
202
|
```ruby
|
199
203
|
class LogRunTime
|
200
204
|
# optional args parameter can be omitted, but if you define initialize
|
@@ -209,23 +213,34 @@ class LogRunTime
|
|
209
213
|
end
|
210
214
|
```
|
211
215
|
|
212
|
-
|
216
|
+
#### Parameters
|
217
|
+
You can pass parameters to events:
|
213
218
|
|
214
219
|
```ruby
|
215
220
|
job = Job.new
|
216
|
-
job.run(:
|
221
|
+
job.run(:defragmentation)
|
217
222
|
```
|
218
223
|
|
219
|
-
In this case
|
224
|
+
All guards and after callbacks will receive these parameters. In this case `set_process` would be called with
|
225
|
+
`:defragmentation` argument.
|
220
226
|
|
221
|
-
|
227
|
+
If the first argument to the event is a state (e.g. `:running` or `:finished`), the first argument is consumed and
|
228
|
+
the state machine will attempt to transition to that state. Add comma separated parameter for guards and callbacks
|
222
229
|
|
230
|
+
```ruby
|
231
|
+
job = Job.new
|
232
|
+
job.run(:running, :defragmentation)
|
233
|
+
```
|
234
|
+
In this case `set_process` won't be called, job will transition to running state and callback will receive
|
235
|
+
`:defragmentation` as parameter
|
236
|
+
|
237
|
+
#### Error Handling
|
223
238
|
In case of an error during the event processing the error is rescued and passed to `:error`
|
224
239
|
callback, which can handle it or re-raise it for further propagation.
|
225
240
|
|
226
241
|
Also, you can define a method that will be called if any event fails:
|
227
242
|
|
228
|
-
```
|
243
|
+
```ruby
|
229
244
|
def aasm_event_failed(event_name, old_state_name)
|
230
245
|
# use custom exception/messages, report metrics, etc
|
231
246
|
end
|
@@ -259,8 +274,8 @@ begin
|
|
259
274
|
new_state enter
|
260
275
|
...update state...
|
261
276
|
event before_success # if persist successful
|
262
|
-
transition success # if persist successful
|
263
|
-
event success # if persist successful
|
277
|
+
transition success # if persist successful, database update not guaranteed
|
278
|
+
event success # if persist successful, database update not guaranteed
|
264
279
|
old_state after_exit
|
265
280
|
new_state after_enter
|
266
281
|
event after
|
@@ -274,6 +289,8 @@ ensure
|
|
274
289
|
end
|
275
290
|
```
|
276
291
|
|
292
|
+
Use event's `after_commit` callback if it should be fired after database update.
|
293
|
+
|
277
294
|
#### The current event triggered
|
278
295
|
|
279
296
|
While running the callbacks you can easily retrieve the name of the event triggered
|
@@ -304,31 +321,31 @@ and then
|
|
304
321
|
Let's assume you want to allow particular transitions only if a defined condition is
|
305
322
|
given. For this you can set up a guard per transition, which will run before actually
|
306
323
|
running the transition. If the guard returns `false` the transition will be
|
307
|
-
denied (raising `AASM::InvalidTransition`
|
324
|
+
denied (raising `AASM::InvalidTransition`):
|
308
325
|
|
309
326
|
```ruby
|
310
327
|
class Cleaner
|
311
328
|
include AASM
|
312
329
|
|
313
330
|
aasm do
|
314
|
-
state :idle, :
|
331
|
+
state :idle, initial: true
|
315
332
|
state :cleaning
|
316
333
|
|
317
334
|
event :clean do
|
318
|
-
transitions :
|
335
|
+
transitions from: :idle, to: :cleaning, guard: :cleaning_needed?
|
319
336
|
end
|
320
337
|
|
321
338
|
event :clean_if_needed do
|
322
|
-
transitions :
|
339
|
+
transitions from: :idle, to: :cleaning do
|
323
340
|
guard do
|
324
341
|
cleaning_needed?
|
325
342
|
end
|
326
343
|
end
|
327
|
-
transitions :
|
344
|
+
transitions from: :idle, to: :idle
|
328
345
|
end
|
329
346
|
|
330
347
|
event :clean_if_dirty do
|
331
|
-
transitions :
|
348
|
+
transitions from: :idle, to: :cleaning, guard: :if_dirty?
|
332
349
|
end
|
333
350
|
end
|
334
351
|
|
@@ -347,7 +364,7 @@ job.clean # => raises AASM::InvalidTransition
|
|
347
364
|
job.may_clean_if_needed? # => true
|
348
365
|
job.clean_if_needed! # idle
|
349
366
|
|
350
|
-
job.clean_if_dirty(:clean) # =>
|
367
|
+
job.clean_if_dirty(:clean) # => raises AASM::InvalidTransition
|
351
368
|
job.clean_if_dirty(:dirty) # => true
|
352
369
|
```
|
353
370
|
|
@@ -357,16 +374,16 @@ You can even provide a number of guards, which all have to succeed to proceed
|
|
357
374
|
def walked_the_dog?; ...; end
|
358
375
|
|
359
376
|
event :sleep do
|
360
|
-
transitions :
|
377
|
+
transitions from: :running, to: :sleeping, guards: [:cleaning_needed?, :walked_the_dog?]
|
361
378
|
end
|
362
379
|
```
|
363
380
|
|
364
381
|
If you want to provide guards for all transitions within an event, you can use event guards
|
365
382
|
|
366
383
|
```ruby
|
367
|
-
event :sleep, :
|
368
|
-
transitions :
|
369
|
-
transitions :
|
384
|
+
event :sleep, guards: [:walked_the_dog?] do
|
385
|
+
transitions from: :running, to: :sleeping, guards: [:cleaning_needed?]
|
386
|
+
transitions from: :cleaning, to: :sleeping
|
370
387
|
end
|
371
388
|
```
|
372
389
|
|
@@ -374,15 +391,30 @@ If you prefer a more Ruby-like guard syntax, you can use `if` and `unless` as we
|
|
374
391
|
|
375
392
|
```ruby
|
376
393
|
event :clean do
|
377
|
-
transitions :
|
394
|
+
transitions from: :running, to: :cleaning, if: :cleaning_needed?
|
378
395
|
end
|
379
396
|
|
380
397
|
event :sleep do
|
381
|
-
transitions :
|
398
|
+
transitions from: :running, to: :sleeping, unless: :cleaning_needed?
|
382
399
|
end
|
383
400
|
end
|
384
401
|
```
|
385
402
|
|
403
|
+
You can invoke a Class instead of a method if the Class responds to `call`
|
404
|
+
|
405
|
+
```ruby
|
406
|
+
event :sleep do
|
407
|
+
transitions from: :running, to: :sleeping, guards: Dog
|
408
|
+
end
|
409
|
+
```
|
410
|
+
```ruby
|
411
|
+
class Dog
|
412
|
+
def call
|
413
|
+
cleaning_needed? && walked?
|
414
|
+
end
|
415
|
+
...
|
416
|
+
end
|
417
|
+
```
|
386
418
|
|
387
419
|
### Transitions
|
388
420
|
|
@@ -395,7 +427,7 @@ class Job
|
|
395
427
|
include AASM
|
396
428
|
|
397
429
|
aasm do
|
398
|
-
state :stage1, :
|
430
|
+
state :stage1, initial: true
|
399
431
|
state :stage2
|
400
432
|
state :stage3
|
401
433
|
state :completed
|
@@ -416,40 +448,67 @@ job.stage1_completed
|
|
416
448
|
job.aasm.current_state # stage3
|
417
449
|
```
|
418
450
|
|
451
|
+
You can define transition from any defined state by omitting `from`:
|
452
|
+
|
453
|
+
```ruby
|
454
|
+
event :abort do
|
455
|
+
transitions to: :aborted
|
456
|
+
end
|
457
|
+
```
|
458
|
+
|
459
|
+
### Display name for state
|
460
|
+
|
461
|
+
You can define display name for state using :display option
|
462
|
+
|
463
|
+
```ruby
|
464
|
+
class Job
|
465
|
+
include AASM
|
466
|
+
|
467
|
+
aasm do
|
468
|
+
state :stage1, initial: true, display: 'First Stage'
|
469
|
+
state :stage2
|
470
|
+
state :stage3
|
471
|
+
end
|
472
|
+
end
|
473
|
+
|
474
|
+
job = Job.new
|
475
|
+
job.aasm.human_state
|
476
|
+
|
477
|
+
```
|
419
478
|
|
420
479
|
### Multiple state machines per class
|
421
480
|
|
422
481
|
Multiple state machines per class are supported. Be aware though that _AASM_ has been
|
423
|
-
built with one state machine per class in mind. Nonetheless, here's how to do it
|
482
|
+
built with one state machine per class in mind. Nonetheless, here's how to do it (see below). Please note that you will need to specify database columns for where your pertinent states will be stored - we have specified two columns `move_state` and `work_state` in the example below. See the [Column name & migration](https://github.com/aasm/aasm#column-name--migration) section for further info.
|
424
483
|
|
425
484
|
```ruby
|
426
485
|
class SimpleMultipleExample
|
427
486
|
include AASM
|
428
|
-
aasm(:move) do
|
429
|
-
state :standing, :
|
487
|
+
aasm(:move, column: 'move_state') do
|
488
|
+
state :standing, initial: true
|
430
489
|
state :walking
|
431
490
|
state :running
|
432
491
|
|
433
492
|
event :walk do
|
434
|
-
transitions :
|
493
|
+
transitions from: :standing, to: :walking
|
435
494
|
end
|
436
495
|
event :run do
|
437
|
-
transitions :
|
496
|
+
transitions from: [:standing, :walking], to: :running
|
438
497
|
end
|
439
498
|
event :hold do
|
440
|
-
transitions :
|
499
|
+
transitions from: [:walking, :running], to: :standing
|
441
500
|
end
|
442
501
|
end
|
443
502
|
|
444
|
-
aasm(:work) do
|
445
|
-
state :sleeping, :
|
503
|
+
aasm(:work, column: 'work_state') do
|
504
|
+
state :sleeping, initial: true
|
446
505
|
state :processing
|
447
506
|
|
448
507
|
event :start do
|
449
|
-
transitions :
|
508
|
+
transitions from: :sleeping, to: :processing
|
450
509
|
end
|
451
510
|
event :stop do
|
452
|
-
transitions :
|
511
|
+
transitions from: :processing, to: :sleeping
|
453
512
|
end
|
454
513
|
end
|
455
514
|
end
|
@@ -458,13 +517,13 @@ simple = SimpleMultipleExample.new
|
|
458
517
|
|
459
518
|
simple.aasm(:move).current_state
|
460
519
|
# => :standing
|
461
|
-
simple.aasm(:work).
|
520
|
+
simple.aasm(:work).current_state
|
462
521
|
# => :sleeping
|
463
522
|
|
464
523
|
simple.start
|
465
524
|
simple.aasm(:move).current_state
|
466
525
|
# => :standing
|
467
|
-
simple.aasm(:work).
|
526
|
+
simple.aasm(:work).current_state
|
468
527
|
# => :processing
|
469
528
|
|
470
529
|
```
|
@@ -482,28 +541,28 @@ Alternatively, you can provide a namespace for each state machine:
|
|
482
541
|
class NamespacedMultipleExample
|
483
542
|
include AASM
|
484
543
|
aasm(:status) do
|
485
|
-
state :unapproved, :
|
544
|
+
state :unapproved, initial: true
|
486
545
|
state :approved
|
487
546
|
|
488
547
|
event :approve do
|
489
|
-
transitions :
|
548
|
+
transitions from: :unapproved, to: :approved
|
490
549
|
end
|
491
550
|
|
492
551
|
event :unapprove do
|
493
|
-
transitions :
|
552
|
+
transitions from: :approved, to: :unapproved
|
494
553
|
end
|
495
554
|
end
|
496
555
|
|
497
556
|
aasm(:review_status, namespace: :review) do
|
498
|
-
state :unapproved, :
|
557
|
+
state :unapproved, initial: true
|
499
558
|
state :approved
|
500
559
|
|
501
560
|
event :approve do
|
502
|
-
transitions :
|
561
|
+
transitions from: :unapproved, to: :approved
|
503
562
|
end
|
504
563
|
|
505
564
|
event :unapprove do
|
506
|
-
transitions :
|
565
|
+
transitions from: :approved, to: :unapproved
|
507
566
|
end
|
508
567
|
end
|
509
568
|
end
|
@@ -523,7 +582,7 @@ All _AASM_ class- and instance-level `aasm` methods accept a state machine selec
|
|
523
582
|
So, for example, to use inspection on a class level, you have to use
|
524
583
|
|
525
584
|
```ruby
|
526
|
-
SimpleMultipleExample.aasm(:
|
585
|
+
SimpleMultipleExample.aasm(:move).states.map(&:name)
|
527
586
|
# => [:standing, :walking, :running]
|
528
587
|
```
|
529
588
|
|
@@ -535,26 +594,26 @@ class Example
|
|
535
594
|
include AASM
|
536
595
|
|
537
596
|
aasm(:work) do
|
538
|
-
state :sleeping, :
|
597
|
+
state :sleeping, initial: true
|
539
598
|
state :processing
|
540
599
|
|
541
600
|
event :start do
|
542
|
-
transitions :
|
601
|
+
transitions from: :sleeping, to: :processing
|
543
602
|
end
|
544
603
|
event :stop do
|
545
|
-
transitions :
|
604
|
+
transitions from: :processing, to: :sleeping
|
546
605
|
end
|
547
606
|
end
|
548
607
|
|
549
608
|
aasm(:question) do
|
550
|
-
state :answered, :
|
609
|
+
state :answered, initial: true
|
551
610
|
state :asked
|
552
611
|
|
553
|
-
event :ask, :
|
554
|
-
transitions :
|
612
|
+
event :ask, binding_event: :start do
|
613
|
+
transitions from: :answered, to: :asked
|
555
614
|
end
|
556
|
-
event :answer, :
|
557
|
-
transitions :
|
615
|
+
event :answer, binding_event: :stop do
|
616
|
+
transitions from: :asked, to: :answered
|
558
617
|
end
|
559
618
|
end
|
560
619
|
end
|
@@ -600,7 +659,7 @@ class CustomAASMBase < AASM::Base
|
|
600
659
|
# A custom transiton that we want available across many AASM models.
|
601
660
|
def count_transitions!
|
602
661
|
klass.class_eval do
|
603
|
-
aasm :
|
662
|
+
aasm with_klass: CustomAASMBase do
|
604
663
|
after_all_transitions :increment_transition_count
|
605
664
|
end
|
606
665
|
end
|
@@ -630,26 +689,26 @@ class CustomAASMBase < AASM::Base
|
|
630
689
|
end
|
631
690
|
```
|
632
691
|
|
633
|
-
When we declare our model that has an AASM state machine, we simply declare the AASM block with a `:
|
692
|
+
When we declare our model that has an AASM state machine, we simply declare the AASM block with a `:with_klass` key to our own class.
|
634
693
|
|
635
694
|
```ruby
|
636
695
|
class SimpleCustomExample
|
637
696
|
include AASM
|
638
697
|
|
639
698
|
# Let's build an AASM state machine with our custom class.
|
640
|
-
aasm :
|
699
|
+
aasm with_klass: CustomAASMBase do
|
641
700
|
requires_guards!
|
642
701
|
count_transitions!
|
643
702
|
|
644
|
-
state :initialised, :
|
703
|
+
state :initialised, initial: true
|
645
704
|
state :filled_out
|
646
705
|
state :authorised
|
647
706
|
|
648
707
|
event :fill_out do
|
649
|
-
transitions :
|
708
|
+
transitions from: :initialised, to: :filled_out, guard: :fillable?
|
650
709
|
end
|
651
710
|
event :authorise do
|
652
|
-
transitions :
|
711
|
+
transitions from: :filled_out, to: :authorised, guard: :authorizable?
|
653
712
|
end
|
654
713
|
end
|
655
714
|
end
|
@@ -661,20 +720,22 @@ end
|
|
661
720
|
AASM comes with support for ActiveRecord and allows automatic persisting of the object's
|
662
721
|
state in the database.
|
663
722
|
|
723
|
+
Add `gem 'after_commit_everywhere', '~> 1.0'` to your Gemfile.
|
724
|
+
|
664
725
|
```ruby
|
665
726
|
class Job < ActiveRecord::Base
|
666
727
|
include AASM
|
667
728
|
|
668
729
|
aasm do # default column: aasm_state
|
669
|
-
state :sleeping, :
|
730
|
+
state :sleeping, initial: true
|
670
731
|
state :running
|
671
732
|
|
672
733
|
event :run do
|
673
|
-
transitions :
|
734
|
+
transitions from: :sleeping, to: :running
|
674
735
|
end
|
675
736
|
|
676
737
|
event :sleep do
|
677
|
-
transitions :
|
738
|
+
transitions from: :running, to: :sleeping
|
678
739
|
end
|
679
740
|
end
|
680
741
|
|
@@ -697,7 +758,7 @@ job.aasm.fire!(:run) # saved
|
|
697
758
|
|
698
759
|
Saving includes running all validations on the `Job` class. If
|
699
760
|
`whiny_persistence` flag is set to `true`, exception is raised in case of
|
700
|
-
failure. If `whiny_persistence` flag is set to false
|
761
|
+
failure. If `whiny_persistence` flag is set to `false`, methods with a bang return
|
701
762
|
`true` if the state transition is successful or `false` if an error occurs.
|
702
763
|
|
703
764
|
If you want make sure the state gets saved without running validations (and
|
@@ -709,22 +770,30 @@ be updated in the database (just like ActiveRecord `update_column` is working).
|
|
709
770
|
class Job < ActiveRecord::Base
|
710
771
|
include AASM
|
711
772
|
|
712
|
-
aasm :
|
713
|
-
state :sleeping, :
|
773
|
+
aasm skip_validation_on_save: true do
|
774
|
+
state :sleeping, initial: true
|
714
775
|
state :running
|
715
776
|
|
716
777
|
event :run do
|
717
|
-
transitions :
|
778
|
+
transitions from: :sleeping, to: :running
|
718
779
|
end
|
719
780
|
|
720
781
|
event :sleep do
|
721
|
-
transitions :
|
782
|
+
transitions from: :running, to: :sleeping
|
722
783
|
end
|
723
784
|
end
|
724
785
|
|
725
786
|
end
|
726
787
|
```
|
727
788
|
|
789
|
+
Also, you can skip the validation at instance level with `some_event_name_without_validation!` method.
|
790
|
+
With this you have the flexibility of having validation for all your transitions by default and then skip it wherever required.
|
791
|
+
Please note that only state column will be updated as mentioned in the above example.
|
792
|
+
|
793
|
+
```ruby
|
794
|
+
job.run_without_validation!
|
795
|
+
```
|
796
|
+
|
728
797
|
If you want to make sure that the _AASM_ column for storing the state is not directly assigned,
|
729
798
|
configure _AASM_ to not allow direct assignment, like this:
|
730
799
|
|
@@ -732,12 +801,12 @@ configure _AASM_ to not allow direct assignment, like this:
|
|
732
801
|
class Job < ActiveRecord::Base
|
733
802
|
include AASM
|
734
803
|
|
735
|
-
aasm :
|
736
|
-
state :sleeping, :
|
804
|
+
aasm no_direct_assignment: true do
|
805
|
+
state :sleeping, initial: true
|
737
806
|
state :running
|
738
807
|
|
739
808
|
event :run do
|
740
|
-
transitions :
|
809
|
+
transitions from: :sleeping, to: :running
|
741
810
|
end
|
742
811
|
end
|
743
812
|
|
@@ -753,6 +822,37 @@ job.aasm_state = :running # => raises AASM::NoDirectAssignmentError
|
|
753
822
|
job.aasm_state # => 'sleeping'
|
754
823
|
```
|
755
824
|
|
825
|
+
### Timestamps
|
826
|
+
|
827
|
+
You can tell _AASM_ to try to write a timestamp whenever a new state is entered.
|
828
|
+
If `timestamps: true` is set, _AASM_ will look for a field named like the new state plus `_at` and try to fill it:
|
829
|
+
|
830
|
+
```ruby
|
831
|
+
class Job < ActiveRecord::Base
|
832
|
+
include AASM
|
833
|
+
|
834
|
+
aasm timestamps: true do
|
835
|
+
state :sleeping, initial: true
|
836
|
+
state :running
|
837
|
+
|
838
|
+
event :run do
|
839
|
+
transitions from: :sleeping, to: :running
|
840
|
+
end
|
841
|
+
end
|
842
|
+
end
|
843
|
+
```
|
844
|
+
|
845
|
+
resulting in this:
|
846
|
+
|
847
|
+
```ruby
|
848
|
+
job = Job.create
|
849
|
+
job.running_at # => nil
|
850
|
+
job.run!
|
851
|
+
job.running_at # => 2020-02-20 20:00:00
|
852
|
+
```
|
853
|
+
|
854
|
+
Missing timestamp fields are silently ignored, so it is not necessary to have setters (such as ActiveRecord columns) for *all* states when using this option.
|
855
|
+
|
756
856
|
#### ActiveRecord enums
|
757
857
|
|
758
858
|
You can use
|
@@ -768,8 +868,8 @@ class Job < ActiveRecord::Base
|
|
768
868
|
running: 99
|
769
869
|
}
|
770
870
|
|
771
|
-
aasm :
|
772
|
-
state :sleeping, :
|
871
|
+
aasm column: :state, enum: true do
|
872
|
+
state :sleeping, initial: true
|
773
873
|
state :running
|
774
874
|
end
|
775
875
|
end
|
@@ -825,6 +925,23 @@ class Job
|
|
825
925
|
end
|
826
926
|
```
|
827
927
|
|
928
|
+
### NoBrainer
|
929
|
+
|
930
|
+
AASM also supports persistence to [RethinkDB](https://www.rethinkdb.com/)
|
931
|
+
if you're using [Nobrainer](http://nobrainer.io/).
|
932
|
+
Make sure to include NoBrainer::Document before you include AASM.
|
933
|
+
|
934
|
+
```ruby
|
935
|
+
class Job
|
936
|
+
include NoBrainer::Document
|
937
|
+
include AASM
|
938
|
+
field :aasm_state
|
939
|
+
aasm do
|
940
|
+
...
|
941
|
+
end
|
942
|
+
end
|
943
|
+
```
|
944
|
+
|
828
945
|
### Redis
|
829
946
|
|
830
947
|
AASM also supports persistence in Redis via
|
@@ -851,7 +968,7 @@ class Job < ActiveRecord::Base
|
|
851
968
|
include AASM
|
852
969
|
|
853
970
|
aasm do
|
854
|
-
state :sleeping, :
|
971
|
+
state :sleeping, initial: true
|
855
972
|
state :running
|
856
973
|
state :cleaning
|
857
974
|
end
|
@@ -880,8 +997,8 @@ defining the `AASM` states, like this:
|
|
880
997
|
class Job < ActiveRecord::Base
|
881
998
|
include AASM
|
882
999
|
|
883
|
-
aasm :
|
884
|
-
state :sleeping, :
|
1000
|
+
aasm create_scopes: false do
|
1001
|
+
state :sleeping, initial: true
|
885
1002
|
state :running
|
886
1003
|
state :cleaning
|
887
1004
|
end
|
@@ -914,11 +1031,11 @@ class Job < ActiveRecord::Base
|
|
914
1031
|
include AASM
|
915
1032
|
|
916
1033
|
aasm do
|
917
|
-
state :sleeping, :
|
1034
|
+
state :sleeping, initial: true
|
918
1035
|
state :running
|
919
1036
|
|
920
|
-
event :run, :
|
921
|
-
transitions :
|
1037
|
+
event :run, after_commit: :notify_about_running_job do
|
1038
|
+
transitions from: :sleeping, to: :running
|
922
1039
|
end
|
923
1040
|
end
|
924
1041
|
|
@@ -940,18 +1057,24 @@ job.run
|
|
940
1057
|
job.save! #notify_about_running_job is not run
|
941
1058
|
```
|
942
1059
|
|
1060
|
+
Please note that `:after_commit` AASM callbacks behaves around custom implementation
|
1061
|
+
of transaction pattern rather than a real-life DB transaction. This fact still causes
|
1062
|
+
the race conditions and redundant callback calls within nested transaction. In order
|
1063
|
+
to fix that it's highly recommended to add `gem 'after_commit_everywhere', '~> 1.0'`
|
1064
|
+
to your `Gemfile`.
|
1065
|
+
|
943
1066
|
If you want to encapsulate state changes within an own transaction, the behavior
|
944
1067
|
of this nested transaction might be confusing. Take a look at
|
945
1068
|
[ActiveRecord Nested Transactions](http://api.rubyonrails.org/classes/ActiveRecord/Transactions/ClassMethods.html)
|
946
1069
|
if you want to know more about this. Nevertheless, AASM by default requires a new transaction
|
947
|
-
`transaction(:
|
1070
|
+
`transaction(requires_new: true)`. You can override this behavior by changing
|
948
1071
|
the configuration
|
949
1072
|
|
950
1073
|
```ruby
|
951
1074
|
class Job < ActiveRecord::Base
|
952
1075
|
include AASM
|
953
1076
|
|
954
|
-
aasm :
|
1077
|
+
aasm requires_new_transaction: false do
|
955
1078
|
...
|
956
1079
|
end
|
957
1080
|
|
@@ -959,9 +1082,9 @@ class Job < ActiveRecord::Base
|
|
959
1082
|
end
|
960
1083
|
```
|
961
1084
|
|
962
|
-
which then leads to `transaction(:
|
1085
|
+
which then leads to `transaction(requires_new: false)`, the Rails default.
|
963
1086
|
|
964
|
-
Additionally, if you do not want any of your
|
1087
|
+
Additionally, if you do not want any of your ActiveRecord actions to be
|
965
1088
|
wrapped in a transaction, you can specify the `use_transactions` flag. This can
|
966
1089
|
be useful if you want want to persist things to the database that happen as a
|
967
1090
|
result of a transaction or callback, even when some error occurs. The
|
@@ -971,7 +1094,7 @@ result of a transaction or callback, even when some error occurs. The
|
|
971
1094
|
class Job < ActiveRecord::Base
|
972
1095
|
include AASM
|
973
1096
|
|
974
|
-
aasm :
|
1097
|
+
aasm use_transactions: false do
|
975
1098
|
...
|
976
1099
|
end
|
977
1100
|
|
@@ -981,7 +1104,7 @@ end
|
|
981
1104
|
|
982
1105
|
### Pessimistic Locking
|
983
1106
|
|
984
|
-
AASM supports [
|
1107
|
+
AASM supports [ActiveRecord pessimistic locking via `with_lock`](http://api.rubyonrails.org/classes/ActiveRecord/Locking/Pessimistic.html#method-i-with_lock) for database persistence layers.
|
985
1108
|
|
986
1109
|
| Option | Purpose |
|
987
1110
|
| ------ | ------- |
|
@@ -994,7 +1117,7 @@ AASM supports [Active Record pessimistic locking via `with_lock`](http://api.rub
|
|
994
1117
|
class Job < ActiveRecord::Base
|
995
1118
|
include AASM
|
996
1119
|
|
997
|
-
aasm :
|
1120
|
+
aasm requires_lock: true do
|
998
1121
|
...
|
999
1122
|
end
|
1000
1123
|
|
@@ -1006,7 +1129,7 @@ end
|
|
1006
1129
|
class Job < ActiveRecord::Base
|
1007
1130
|
include AASM
|
1008
1131
|
|
1009
|
-
aasm :
|
1132
|
+
aasm requires_lock: 'FOR UPDATE NOWAIT' do
|
1010
1133
|
...
|
1011
1134
|
end
|
1012
1135
|
|
@@ -1024,18 +1147,21 @@ this by defining your favorite column name, using `:column` like this:
|
|
1024
1147
|
class Job < ActiveRecord::Base
|
1025
1148
|
include AASM
|
1026
1149
|
|
1027
|
-
aasm :
|
1150
|
+
aasm column: :my_state do
|
1028
1151
|
...
|
1029
1152
|
end
|
1030
1153
|
|
1031
|
-
aasm :another_state_machine, column:
|
1154
|
+
aasm :another_state_machine, column: :second_state do
|
1032
1155
|
...
|
1033
1156
|
end
|
1034
1157
|
end
|
1035
1158
|
```
|
1036
1159
|
|
1037
1160
|
Whatever column name is used, make sure to add a migration to provide this column
|
1038
|
-
(of type `string`)
|
1161
|
+
(of type `string`).
|
1162
|
+
Do not add default value for column at the database level. If you add default
|
1163
|
+
value in database then AASM callbacks on the initial state will not be fired upon
|
1164
|
+
instantiation of the model.
|
1039
1165
|
|
1040
1166
|
```ruby
|
1041
1167
|
class AddJobState < ActiveRecord::Migration
|
@@ -1049,6 +1175,13 @@ class AddJobState < ActiveRecord::Migration
|
|
1049
1175
|
end
|
1050
1176
|
```
|
1051
1177
|
|
1178
|
+
### Log State Changes
|
1179
|
+
|
1180
|
+
Logging state change can be done using [paper_trail](https://github.com/paper-trail-gem/paper_trail) gem
|
1181
|
+
|
1182
|
+
Example of implementation can be found here [https://github.com/nitsujri/aasm-papertrail-example](https://github.com/nitsujri/aasm-papertrail-example)
|
1183
|
+
|
1184
|
+
|
1052
1185
|
### Inspection
|
1053
1186
|
|
1054
1187
|
AASM supports query methods for states and events
|
@@ -1060,19 +1193,19 @@ class Job
|
|
1060
1193
|
include AASM
|
1061
1194
|
|
1062
1195
|
aasm do
|
1063
|
-
state :sleeping, :
|
1196
|
+
state :sleeping, initial: true
|
1064
1197
|
state :running, :cleaning
|
1065
1198
|
|
1066
1199
|
event :run do
|
1067
|
-
transitions :
|
1200
|
+
transitions from: :sleeping, to: :running
|
1068
1201
|
end
|
1069
1202
|
|
1070
1203
|
event :clean do
|
1071
|
-
transitions :
|
1204
|
+
transitions from: :running, to: :cleaning, guard: :cleaning_needed?
|
1072
1205
|
end
|
1073
1206
|
|
1074
1207
|
event :sleep do
|
1075
|
-
transitions :
|
1208
|
+
transitions from: [:running, :cleaning], to: :sleeping
|
1076
1209
|
end
|
1077
1210
|
end
|
1078
1211
|
|
@@ -1090,15 +1223,19 @@ Job.aasm.states.map(&:name)
|
|
1090
1223
|
job = Job.new
|
1091
1224
|
|
1092
1225
|
# show all permitted states (from initial state)
|
1093
|
-
job.aasm.states(:
|
1226
|
+
job.aasm.states(permitted: true).map(&:name)
|
1094
1227
|
#=> [:running]
|
1095
1228
|
|
1229
|
+
# List all the permitted transitions(event and state pairs) from initial state
|
1230
|
+
job.aasm.permitted_transitions
|
1231
|
+
#=> [{ :event => :run, :state => :running }]
|
1232
|
+
|
1096
1233
|
job.run
|
1097
|
-
job.aasm.states(:
|
1234
|
+
job.aasm.states(permitted: true).map(&:name)
|
1098
1235
|
#=> [:sleeping]
|
1099
1236
|
|
1100
1237
|
# show all non permitted states
|
1101
|
-
job.aasm.states(:
|
1238
|
+
job.aasm.states(permitted: false).map(&:name)
|
1102
1239
|
#=> [:cleaning]
|
1103
1240
|
|
1104
1241
|
# show all possible (triggerable) events from the current state
|
@@ -1106,23 +1243,23 @@ job.aasm.events.map(&:name)
|
|
1106
1243
|
#=> [:clean, :sleep]
|
1107
1244
|
|
1108
1245
|
# show all permitted events
|
1109
|
-
job.aasm.events(:
|
1246
|
+
job.aasm.events(permitted: true).map(&:name)
|
1110
1247
|
#=> [:sleep]
|
1111
1248
|
|
1112
1249
|
# show all non permitted events
|
1113
|
-
job.aasm.events(:
|
1250
|
+
job.aasm.events(permitted: false).map(&:name)
|
1114
1251
|
#=> [:clean]
|
1115
1252
|
|
1116
1253
|
# show all possible events except a specific one
|
1117
|
-
job.aasm.events(:
|
1254
|
+
job.aasm.events(reject: :sleep).map(&:name)
|
1118
1255
|
#=> [:clean]
|
1119
1256
|
|
1120
1257
|
# list states for select
|
1121
1258
|
Job.aasm.states_for_select
|
1122
|
-
|
1259
|
+
#=> [["Sleeping", "sleeping"], ["Running", "running"], ["Cleaning", "cleaning"]]
|
1123
1260
|
|
1124
1261
|
# show permitted states with guard parameter
|
1125
|
-
job.aasm.states({:
|
1262
|
+
job.aasm.states({permitted: true}, guard_parameter).map(&:name)
|
1126
1263
|
```
|
1127
1264
|
|
1128
1265
|
|
@@ -1135,7 +1272,7 @@ use
|
|
1135
1272
|
class Job
|
1136
1273
|
include AASM
|
1137
1274
|
|
1138
|
-
aasm :
|
1275
|
+
aasm logger: Rails.logger do
|
1139
1276
|
...
|
1140
1277
|
end
|
1141
1278
|
end
|
@@ -1159,7 +1296,15 @@ the 'instance method symbol / string' way whenever possible when defining guardi
|
|
1159
1296
|
|
1160
1297
|
#### RSpec
|
1161
1298
|
|
1162
|
-
AASM provides some matchers for [RSpec](http://rspec.info):
|
1299
|
+
AASM provides some matchers for [RSpec](http://rspec.info):
|
1300
|
+
* `transition_from`,
|
1301
|
+
* `have_state`, `allow_event`
|
1302
|
+
* and `allow_transition_to`.
|
1303
|
+
|
1304
|
+
##### Installation Instructions:
|
1305
|
+
* Add `require 'aasm/rspec'` to your `spec_helper.rb` file.
|
1306
|
+
|
1307
|
+
##### Examples Of Usage in Rspec:
|
1163
1308
|
|
1164
1309
|
```ruby
|
1165
1310
|
# classes with only the default state machine
|
@@ -1172,7 +1317,7 @@ expect(job).to allow_event :run
|
|
1172
1317
|
expect(job).to_not allow_event :clean
|
1173
1318
|
expect(job).to allow_transition_to(:running)
|
1174
1319
|
expect(job).to_not allow_transition_to(:cleaning)
|
1175
|
-
# on_event also accept arguments
|
1320
|
+
# on_event also accept multiple arguments
|
1176
1321
|
expect(job).to transition_from(:sleeping).to(:running).on_event(:run, :defragmentation)
|
1177
1322
|
|
1178
1323
|
# classes with multiple state machine
|
@@ -1193,6 +1338,9 @@ expect(multiple).to allow_event(:start).on(:move)
|
|
1193
1338
|
expect(multiple).to_not allow_event(:stop).on(:move)
|
1194
1339
|
expect(multiple).to allow_transition_to(:processing).on(:move)
|
1195
1340
|
expect(multiple).to_not allow_transition_to(:sleeping).on(:move)
|
1341
|
+
# allow_event also accepts arguments
|
1342
|
+
expect(job).to allow_event(:run).with(:defragmentation)
|
1343
|
+
|
1196
1344
|
```
|
1197
1345
|
|
1198
1346
|
#### Minitest
|
@@ -1203,7 +1351,10 @@ AASM provides assertions and rspec-like expectations for [Minitest](https://gith
|
|
1203
1351
|
|
1204
1352
|
List of supported assertions: `assert_have_state`, `refute_have_state`, `assert_transitions_from`, `refute_transitions_from`, `assert_event_allowed`, `refute_event_allowed`, `assert_transition_to_allowed`, `refute_transition_to_allowed`.
|
1205
1353
|
|
1206
|
-
|
1354
|
+
|
1355
|
+
##### Examples Of Usage (Minitest):
|
1356
|
+
|
1357
|
+
Add `require 'aasm/minitest'` to your `test_helper.rb` file and use them like this:
|
1207
1358
|
|
1208
1359
|
```ruby
|
1209
1360
|
# classes with only the default state machine
|
@@ -1310,7 +1461,15 @@ After installing AASM you can run generator:
|
|
1310
1461
|
```
|
1311
1462
|
Replace NAME with the Model name, COLUMN_NAME is optional(default is 'aasm_state').
|
1312
1463
|
This will create a model (if one does not exist) and configure it with aasm block.
|
1313
|
-
For
|
1464
|
+
For ActiveRecord orm a migration file is added to add aasm state column to table.
|
1465
|
+
|
1466
|
+
### Docker
|
1467
|
+
|
1468
|
+
Run test suite easily on docker
|
1469
|
+
```
|
1470
|
+
1. docker-compose build aasm
|
1471
|
+
2. docker-compose run --rm aasm
|
1472
|
+
```
|
1314
1473
|
|
1315
1474
|
## Latest changes ##
|
1316
1475
|
|
@@ -1332,6 +1491,12 @@ Feel free to
|
|
1332
1491
|
* [Anil Maurya](http://github.com/anilmaurya) (since 2016)
|
1333
1492
|
|
1334
1493
|
|
1494
|
+
|
1495
|
+
## Stargazers over time
|
1496
|
+
|
1497
|
+
[![Stargazers over time](https://starchart.cc/aasm/aasm.svg)](https://starchart.cc/aasm/aasm)
|
1498
|
+
|
1499
|
+
|
1335
1500
|
## [Contributing](CONTRIBUTING.md)
|
1336
1501
|
|
1337
1502
|
## Warranty ##
|