aasm 4.5.1 → 5.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/LICENSE +1 -1
- data/README.md +809 -129
- data/lib/aasm/aasm.rb +74 -37
- data/lib/aasm/base.rb +188 -41
- data/lib/aasm/configuration.rb +27 -2
- data/lib/aasm/core/event.rb +75 -47
- 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 +22 -13
- data/lib/aasm/core/transition.rb +30 -23
- data/lib/aasm/dsl_helper.rb +24 -22
- data/lib/aasm/errors.rb +8 -5
- data/lib/aasm/instance_base.rb +63 -15
- data/lib/aasm/localizer.rb +13 -3
- data/lib/aasm/minitest/allow_event.rb +13 -0
- data/lib/aasm/minitest/allow_transition_to.rb +13 -0
- data/lib/aasm/minitest/have_state.rb +13 -0
- data/lib/aasm/minitest/transition_from.rb +21 -0
- data/lib/aasm/minitest.rb +5 -0
- data/lib/aasm/minitest_spec.rb +15 -0
- data/lib/aasm/persistence/active_record_persistence.rb +87 -79
- data/lib/aasm/persistence/base.rb +30 -30
- data/lib/aasm/persistence/core_data_query_persistence.rb +94 -0
- data/lib/aasm/persistence/dynamoid_persistence.rb +92 -0
- data/lib/aasm/persistence/mongoid_persistence.rb +49 -35
- data/lib/aasm/persistence/no_brainer_persistence.rb +105 -0
- data/lib/aasm/persistence/orm.rb +154 -0
- data/lib/aasm/persistence/plain_persistence.rb +2 -1
- data/lib/aasm/persistence/redis_persistence.rb +112 -0
- data/lib/aasm/persistence/sequel_persistence.rb +37 -67
- data/lib/aasm/persistence.rb +20 -5
- 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 +8 -4
- data/lib/aasm/state_machine.rb +6 -12
- data/lib/aasm/state_machine_store.rb +76 -0
- data/lib/aasm/version.rb +1 -1
- data/lib/aasm.rb +8 -2
- data/lib/generators/aasm/aasm_generator.rb +16 -0
- data/lib/generators/aasm/orm_helpers.rb +41 -0
- data/lib/generators/active_record/aasm_generator.rb +40 -0
- data/lib/generators/active_record/templates/migration.rb +8 -0
- data/lib/generators/active_record/templates/migration_existing.rb +5 -0
- data/lib/generators/mongoid/aasm_generator.rb +28 -0
- data/lib/generators/nobrainer/aasm_generator.rb +28 -0
- data/lib/motion-aasm.rb +37 -0
- metadata +104 -259
- data/.document +0 -6
- data/.gitignore +0 -19
- data/.travis.yml +0 -37
- data/API +0 -34
- data/CHANGELOG.md +0 -272
- data/CODE_OF_CONDUCT.md +0 -13
- data/Gemfile +0 -15
- data/HOWTO +0 -12
- data/PLANNED_CHANGES.md +0 -11
- data/README_FROM_VERSION_3_TO_4.md +0 -240
- data/Rakefile +0 -26
- data/aasm.gemspec +0 -31
- data/callbacks.txt +0 -51
- data/gemfiles/rails_3.2.gemfile +0 -14
- data/gemfiles/rails_4.0.gemfile +0 -12
- data/gemfiles/rails_4.0_mongo_mapper.gemfile +0 -14
- data/gemfiles/rails_4.1.gemfile +0 -12
- data/gemfiles/rails_4.1_mongo_mapper.gemfile +0 -14
- data/gemfiles/rails_4.2.gemfile +0 -12
- data/gemfiles/rails_4.2_mongo_mapper.gemfile +0 -14
- data/gemfiles/rails_4.2_mongoid_5.gemfile +0 -12
- data/lib/aasm/persistence/mongo_mapper_persistence.rb +0 -157
- data/spec/database.rb +0 -63
- data/spec/database.yml +0 -3
- data/spec/en.yml +0 -9
- data/spec/en_deprecated_style.yml +0 -10
- 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 -33
- 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/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/simple_new_dsl.rb +0 -17
- data/spec/models/active_record/thief.rb +0 -29
- data/spec/models/active_record/transient.rb +0 -6
- data/spec/models/active_record/with_enum.rb +0 -39
- 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/writer.rb +0 -6
- data/spec/models/basic_two_state_machines_example.rb +0 -25
- data/spec/models/callbacks/basic.rb +0 -78
- data/spec/models/callbacks/basic_multiple.rb +0 -75
- data/spec/models/callbacks/guard_within_block.rb +0 -66
- data/spec/models/callbacks/guard_within_block_multiple.rb +0 -66
- data/spec/models/callbacks/multiple_transitions_transition_guard.rb +0 -65
- 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 -61
- data/spec/models/callbacks/with_args_multiple.rb +0 -61
- data/spec/models/callbacks/with_state_arg.rb +0 -26
- 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/foo.rb +0 -92
- data/spec/models/foo_callback_multiple.rb +0 -45
- data/spec/models/guardian.rb +0 -48
- data/spec/models/guardian_multiple.rb +0 -48
- data/spec/models/initial_state_proc.rb +0 -31
- data/spec/models/invalid_persistor.rb +0 -31
- data/spec/models/mongo_mapper/complex_mongo_mapper_example.rb +0 -37
- data/spec/models/mongo_mapper/no_scope_mongo_mapper.rb +0 -21
- data/spec/models/mongo_mapper/simple_mongo_mapper.rb +0 -23
- data/spec/models/mongo_mapper/simple_new_dsl_mongo_mapper.rb +0 -25
- data/spec/models/mongoid/complex_mongoid_example.rb +0 -37
- data/spec/models/mongoid/no_scope_mongoid.rb +0 -21
- data/spec/models/mongoid/simple_mongoid.rb +0 -23
- data/spec/models/mongoid/simple_new_dsl_mongoid.rb +0 -25
- 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 -29
- 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/sequel/complex_sequel_example.rb +0 -45
- data/spec/models/sequel/sequel_multiple.rb +0 -25
- data/spec/models/sequel/sequel_simple.rb +0 -25
- data/spec/models/silencer.rb +0 -27
- data/spec/models/simple_example.rb +0 -15
- data/spec/models/simple_multiple_example.rb +0 -30
- data/spec/models/state_machine_with_failed_event.rb +0 -12
- data/spec/models/sub_class.rb +0 -7
- 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/transactor.rb +0 -53
- data/spec/models/valid_state_name.rb +0 -23
- data/spec/models/validator.rb +0 -79
- data/spec/models/worker.rb +0 -2
- data/spec/spec_helper.rb +0 -25
- data/spec/unit/api_spec.rb +0 -77
- data/spec/unit/basic_two_state_machines_example_spec.rb +0 -10
- data/spec/unit/callback_multiple_spec.rb +0 -295
- data/spec/unit/callbacks_spec.rb +0 -296
- data/spec/unit/complex_example_spec.rb +0 -84
- data/spec/unit/complex_multiple_example_spec.rb +0 -99
- 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 -11
- data/spec/unit/event_spec.rb +0 -322
- data/spec/unit/guard_multiple_spec.rb +0 -60
- data/spec/unit/guard_spec.rb +0 -60
- 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 -111
- data/spec/unit/localizer_spec.rb +0 -76
- data/spec/unit/memory_leak_spec.rb +0 -38
- data/spec/unit/new_dsl_spec.rb +0 -12
- data/spec/unit/persistence/active_record_persistence_multiple_spec.rb +0 -573
- data/spec/unit/persistence/active_record_persistence_spec.rb +0 -552
- data/spec/unit/persistence/mongo_mapper_persistence_multiple_spec.rb +0 -146
- data/spec/unit/persistence/mongo_mapper_persistence_spec.rb +0 -93
- data/spec/unit/persistence/mongoid_persistence_multiple_spec.rb +0 -127
- data/spec/unit/persistence/mongoid_persistence_spec.rb +0 -79
- data/spec/unit/persistence/sequel_persistence_multiple_spec.rb +0 -153
- data/spec/unit/persistence/sequel_persistence_spec.rb +0 -100
- data/spec/unit/readme_spec.rb +0 -42
- data/spec/unit/reloading_spec.rb +0 -15
- data/spec/unit/rspec_matcher_spec.rb +0 -79
- data/spec/unit/simple_example_spec.rb +0 -42
- data/spec/unit/simple_multiple_example_spec.rb +0 -63
- data/spec/unit/state_spec.rb +0 -89
- data/spec/unit/subclassing_multiple_spec.rb +0 -39
- data/spec/unit/subclassing_spec.rb +0 -31
- data/spec/unit/transition_spec.rb +0 -291
@@ -1,5 +1,4 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require 'aasm/persistence/orm'
|
3
2
|
module AASM
|
4
3
|
module Persistence
|
5
4
|
module ActiveRecordPersistence
|
@@ -30,101 +29,115 @@ module AASM
|
|
30
29
|
#
|
31
30
|
def self.included(base)
|
32
31
|
base.send(:include, AASM::Persistence::Base)
|
32
|
+
base.send(:include, AASM::Persistence::ORM)
|
33
33
|
base.send(:include, AASM::Persistence::ActiveRecordPersistence::InstanceMethods)
|
34
|
+
base.extend AASM::Persistence::ActiveRecordPersistence::ClassMethods
|
34
35
|
|
35
|
-
base.after_initialize
|
36
|
-
aasm_ensure_initial_state
|
37
|
-
end
|
36
|
+
base.after_initialize :aasm_ensure_initial_state
|
38
37
|
|
39
38
|
# ensure state is in the list of states
|
40
39
|
base.validate :aasm_validate_states
|
41
40
|
end
|
42
41
|
|
43
|
-
module
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
# foo.aasm.current_state # => :closed
|
51
|
-
# Foo.find(1).aasm.current_state # => :closed
|
52
|
-
#
|
53
|
-
# NOTE: intended to be called from an event
|
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
|
57
|
-
|
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
|
42
|
+
module ClassMethods
|
43
|
+
def aasm_create_scope(state_machine_name, scope_name)
|
44
|
+
if ActiveRecord::VERSION::MAJOR >= 3
|
45
|
+
conditions = { aasm(state_machine_name).attribute_name => scope_name.to_s }
|
46
|
+
class_eval do
|
47
|
+
scope scope_name, lambda { where(table_name => conditions) }
|
48
|
+
end
|
61
49
|
else
|
62
|
-
|
50
|
+
conditions = {
|
51
|
+
table_name => { aasm(state_machine_name).attribute_name => scope_name.to_s }
|
52
|
+
}
|
53
|
+
class_eval do
|
54
|
+
named_scope scope_name, :conditions => conditions
|
55
|
+
end
|
63
56
|
end
|
64
|
-
|
65
|
-
|
66
|
-
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
module InstanceMethods
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def aasm_execute_after_commit
|
65
|
+
begin
|
66
|
+
require 'after_commit_everywhere'
|
67
|
+
raise LoadError unless Gem::Version.new(::AfterCommitEverywhere::VERSION) >= Gem::Version.new('0.1.5')
|
68
|
+
|
69
|
+
self.extend ::AfterCommitEverywhere
|
70
|
+
after_commit do
|
71
|
+
yield
|
72
|
+
end
|
73
|
+
rescue LoadError
|
74
|
+
warn <<-MSG
|
75
|
+
[DEPRECATION] :after_commit AASM callback is not safe in terms of race conditions and redundant calls.
|
76
|
+
Please add `gem 'after_commit_everywhere', '~> 1.0'` to your Gemfile in order to fix that.
|
77
|
+
MSG
|
78
|
+
yield
|
67
79
|
end
|
80
|
+
end
|
68
81
|
|
69
|
-
|
82
|
+
def aasm_raise_invalid_record
|
83
|
+
raise ActiveRecord::RecordInvalid.new(self)
|
70
84
|
end
|
71
85
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
def
|
85
|
-
|
86
|
+
def aasm_save
|
87
|
+
self.save
|
88
|
+
end
|
89
|
+
|
90
|
+
def aasm_update_column(attribute_name, value)
|
91
|
+
self.class.unscoped.where(self.class.primary_key => self.id).update_all(attribute_name => value) == 1
|
92
|
+
end
|
93
|
+
|
94
|
+
def aasm_read_attribute(name)
|
95
|
+
read_attribute(name)
|
96
|
+
end
|
97
|
+
|
98
|
+
def aasm_write_attribute(name, value)
|
99
|
+
write_attribute(name, value)
|
100
|
+
end
|
101
|
+
|
102
|
+
def aasm_transaction(requires_new, requires_lock)
|
103
|
+
self.class.transaction(:requires_new => requires_new) do
|
104
|
+
lock!(requires_lock) if requires_lock
|
105
|
+
yield
|
106
|
+
end
|
86
107
|
end
|
87
108
|
|
88
|
-
private
|
89
109
|
def aasm_enum(name=:default)
|
90
|
-
case AASM::
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
110
|
+
case AASM::StateMachineStore.fetch(self.class, true).machine(name).config.enum
|
111
|
+
when false then nil
|
112
|
+
when true then aasm_guess_enum_method(name)
|
113
|
+
when nil then aasm_guess_enum_method(name) if aasm_column_looks_like_enum(name)
|
114
|
+
else AASM::StateMachineStore.fetch(self.class, true).machine(name).config.enum
|
95
115
|
end
|
96
116
|
end
|
97
117
|
|
98
118
|
def aasm_column_looks_like_enum(name=:default)
|
99
|
-
self.class.
|
119
|
+
column_name = self.class.aasm(name).attribute_name.to_s
|
120
|
+
column = self.class.columns_hash[column_name]
|
121
|
+
raise NoMethodError.new("undefined method '#{column_name}' for #{self.class}") if column.nil?
|
122
|
+
column.type == :integer
|
100
123
|
end
|
101
124
|
|
102
125
|
def aasm_guess_enum_method(name=:default)
|
103
126
|
self.class.aasm(name).attribute_name.to_s.pluralize.to_sym
|
104
127
|
end
|
105
128
|
|
106
|
-
def aasm_skipping_validations(state_machine_name)
|
107
|
-
AASM::StateMachine[self.class][state_machine_name].config.skip_validation_on_save
|
108
|
-
end
|
109
|
-
|
110
|
-
def aasm_write_attribute(state, name=:default)
|
111
|
-
write_attribute(self.class.aasm(name).attribute_name, aasm_raw_attribute_value(state, name))
|
112
|
-
end
|
113
|
-
|
114
129
|
def aasm_raw_attribute_value(state, name=:default)
|
115
130
|
if aasm_enum(name)
|
116
131
|
self.class.send(aasm_enum(name))[state]
|
117
132
|
else
|
118
|
-
|
133
|
+
super
|
119
134
|
end
|
120
135
|
end
|
121
136
|
|
122
137
|
# Ensures that if the aasm_state column is nil and the record is new
|
123
|
-
#
|
138
|
+
# then the initial state gets populated after initialization
|
124
139
|
#
|
125
140
|
# foo = Foo.new
|
126
|
-
# foo.aasm_state # => nil
|
127
|
-
# foo.valid?
|
128
141
|
# foo.aasm_state # => "open" (where :open is the initial state)
|
129
142
|
#
|
130
143
|
#
|
@@ -135,39 +148,34 @@ module AASM
|
|
135
148
|
# foo.aasm_state # => nil
|
136
149
|
#
|
137
150
|
def aasm_ensure_initial_state
|
138
|
-
AASM::
|
151
|
+
AASM::StateMachineStore.fetch(self.class, true).machine_names.each do |state_machine_name|
|
139
152
|
# checking via respond_to? does not work in Rails <= 3
|
140
153
|
# 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
|
154
|
+
if aasm_column_is_blank?(state_machine_name)
|
142
155
|
aasm(state_machine_name).enter_initial_state
|
143
156
|
end
|
144
157
|
end
|
145
158
|
end
|
146
159
|
|
147
|
-
def
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
event = self.class.aasm(state_machine_name).state_machine.events[name]
|
152
|
-
event.fire_callbacks(:after_commit, self, *args)
|
153
|
-
end
|
154
|
-
|
155
|
-
success
|
156
|
-
end
|
157
|
-
|
158
|
-
def requires_new?(state_machine_name)
|
159
|
-
AASM::StateMachine[self.class][state_machine_name].config.requires_new_transaction
|
160
|
+
def aasm_column_is_blank?(state_machine_name)
|
161
|
+
attribute_name = self.class.aasm(state_machine_name).attribute_name
|
162
|
+
attribute_names.include?(attribute_name.to_s) &&
|
163
|
+
(send(attribute_name).respond_to?(:empty?) ? !!send(attribute_name).empty? : !send(attribute_name))
|
160
164
|
end
|
161
165
|
|
162
166
|
def aasm_validate_states
|
163
|
-
AASM::
|
167
|
+
AASM::StateMachineStore.fetch(self.class, true).machine_names.each do |state_machine_name|
|
164
168
|
unless aasm_skipping_validations(state_machine_name)
|
165
|
-
if
|
166
|
-
self.errors.add(AASM::
|
169
|
+
if aasm_invalid_state?(state_machine_name)
|
170
|
+
self.errors.add(AASM::StateMachineStore.fetch(self.class, true).machine(state_machine_name).config.column , "is invalid")
|
167
171
|
end
|
168
172
|
end
|
169
173
|
end
|
170
174
|
end
|
175
|
+
|
176
|
+
def aasm_invalid_state?(state_machine_name)
|
177
|
+
aasm(state_machine_name).current_state && !aasm(state_machine_name).states.include?(aasm(state_machine_name).current_state)
|
178
|
+
end
|
171
179
|
end # InstanceMethods
|
172
180
|
|
173
181
|
end
|
@@ -34,13 +34,17 @@ module AASM
|
|
34
34
|
# This allows for nil aasm states - be sure to add validation to your model
|
35
35
|
def aasm_read_state(name=:default)
|
36
36
|
state = send(self.class.aasm(name).attribute_name)
|
37
|
-
if
|
38
|
-
|
37
|
+
if !state || state.empty?
|
38
|
+
aasm_new_record? ? aasm(name).determine_state_name(self.class.aasm(name).initial_state) : nil
|
39
39
|
else
|
40
|
-
state.
|
40
|
+
state.to_sym
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
+
def aasm_new_record?
|
45
|
+
new_record?
|
46
|
+
end
|
47
|
+
|
44
48
|
module ClassMethods
|
45
49
|
def aasm_column(attribute_name=nil)
|
46
50
|
warn "[DEPRECATION] aasm_column is deprecated. Use aasm.attribute_name instead"
|
@@ -53,37 +57,33 @@ module AASM
|
|
53
57
|
|
54
58
|
class Base
|
55
59
|
# make sure to create a (named) scope for each state
|
56
|
-
def state_with_scope(
|
57
|
-
state_without_scope(
|
58
|
-
|
59
|
-
|
60
|
-
if @klass.ancestors.map {|klass| klass.to_s}.include?("ActiveRecord::Base")
|
61
|
-
conditions = {"#{@klass.table_name}.#{@klass.aasm(@name).attribute_name}" => name.to_s}
|
62
|
-
if ActiveRecord::VERSION::MAJOR >= 3
|
63
|
-
@klass.class_eval do
|
64
|
-
scope name, lambda { where(conditions) }
|
65
|
-
end
|
66
|
-
else
|
67
|
-
@klass.class_eval do
|
68
|
-
named_scope name, :conditions => conditions
|
69
|
-
end
|
70
|
-
end
|
71
|
-
elsif @klass.ancestors.map {|klass| klass.to_s}.include?("Mongoid::Document")
|
72
|
-
klass = @klass
|
73
|
-
state_machine_name = @name
|
74
|
-
scope_options = lambda {
|
75
|
-
klass.send(:where, {klass.aasm(state_machine_name).attribute_name.to_sym => name.to_s})
|
76
|
-
}
|
77
|
-
@klass.send(:scope, name, scope_options)
|
78
|
-
elsif @klass.ancestors.map {|klass| klass.to_s}.include?("MongoMapper::Document")
|
79
|
-
conditions = { @klass.aasm(@name).attribute_name.to_sym => name.to_s }
|
80
|
-
@klass.scope(name, lambda { @klass.where(conditions) })
|
81
|
-
end
|
82
|
-
|
60
|
+
def state_with_scope(*args)
|
61
|
+
names = state_without_scope(*args)
|
62
|
+
names.each do |name|
|
63
|
+
create_scopes(name)
|
83
64
|
end
|
84
65
|
end
|
85
66
|
alias_method :state_without_scope, :state
|
86
67
|
alias_method :state, :state_with_scope
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def create_scope?(name)
|
72
|
+
@state_machine.config.create_scopes && !@klass.respond_to?(name) && @klass.respond_to?(:aasm_create_scope)
|
73
|
+
end
|
74
|
+
|
75
|
+
def create_scope(name)
|
76
|
+
@klass.aasm_create_scope(@name, name) if create_scope?(name)
|
77
|
+
end
|
78
|
+
|
79
|
+
def create_scopes(name)
|
80
|
+
if namespace?
|
81
|
+
# Create default scopes even when namespace? for backward compatibility
|
82
|
+
namepaced_name = "#{namespace}_#{name}"
|
83
|
+
create_scope(namepaced_name)
|
84
|
+
end
|
85
|
+
create_scope(name)
|
86
|
+
end
|
87
87
|
end # Base
|
88
88
|
|
89
89
|
end # AASM
|
@@ -0,0 +1,94 @@
|
|
1
|
+
module AASM
|
2
|
+
module Persistence
|
3
|
+
module CoreDataQueryPersistence
|
4
|
+
# This method:
|
5
|
+
#
|
6
|
+
# * extends the model with ClassMethods
|
7
|
+
# * includes InstanceMethods
|
8
|
+
#
|
9
|
+
# Adds
|
10
|
+
#
|
11
|
+
# after_initialize :aasm_ensure_initial_state
|
12
|
+
#
|
13
|
+
|
14
|
+
def self.included(base)
|
15
|
+
base.send(:include, AASM::Persistence::Base)
|
16
|
+
base.send(:include, AASM::Persistence::CoreDataQueryPersistence::InstanceMethods)
|
17
|
+
base.extend AASM::Persistence::CoreDataQueryPersistence::ClassMethods
|
18
|
+
|
19
|
+
base.after_initialize :aasm_ensure_initial_state
|
20
|
+
end
|
21
|
+
|
22
|
+
module ClassMethods
|
23
|
+
def aasm_create_scope(state_machine_name, scope_name)
|
24
|
+
scope(scope_name.to_sym, lambda { where(aasm(state_machine_name).attribute_name.to_sym).eq(scope_name.to_s) })
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
module InstanceMethods
|
29
|
+
|
30
|
+
# Writes <tt>state</tt> to the state column and persists it to the database
|
31
|
+
# using update_attribute (which bypasses validation)
|
32
|
+
#
|
33
|
+
# foo = Foo.find(1)
|
34
|
+
# foo.aasm.current_state # => :opened
|
35
|
+
# foo.close!
|
36
|
+
# foo.aasm.current_state # => :closed
|
37
|
+
# Foo.find(1).aasm.current_state # => :closed
|
38
|
+
#
|
39
|
+
# NOTE: intended to be called from an event
|
40
|
+
def aasm_write_state(state, name=:default)
|
41
|
+
raise "Cowardly refusing to save the current CoreDataQuery context"
|
42
|
+
aasm_write_state_without_persistence(state, name)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Writes <tt>state</tt> to the state column, but does not persist it to the database
|
46
|
+
#
|
47
|
+
# foo = Foo.find(1)
|
48
|
+
# foo.aasm.current_state # => :opened
|
49
|
+
# foo.close
|
50
|
+
# foo.aasm.current_state # => :closed
|
51
|
+
# Foo.find(1).aasm.current_state # => :opened
|
52
|
+
# foo.save
|
53
|
+
# foo.aasm.current_state # => :closed
|
54
|
+
# Foo.find(1).aasm.current_state # => :closed
|
55
|
+
#
|
56
|
+
# NOTE: intended to be called from an event
|
57
|
+
def aasm_write_state_without_persistence(state, name=:default)
|
58
|
+
write_attribute(self.class.aasm(name).attribute_name, state.to_s)
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
# Ensures that if the aasm_state column is nil and the record is new
|
64
|
+
# that the initial state gets populated before validation on create
|
65
|
+
#
|
66
|
+
# foo = Foo.new
|
67
|
+
# foo.aasm_state # => nil
|
68
|
+
# foo.valid?
|
69
|
+
# foo.aasm_state # => "open" (where :open is the initial state)
|
70
|
+
#
|
71
|
+
#
|
72
|
+
# foo = Foo.find(:first)
|
73
|
+
# foo.aasm_state # => 1
|
74
|
+
# foo.aasm_state = nil
|
75
|
+
# foo.valid?
|
76
|
+
# foo.aasm_state # => nil
|
77
|
+
#
|
78
|
+
def aasm_ensure_initial_state
|
79
|
+
AASM::StateMachineStore.fetch(self.class, true).machine_names.each do |state_machine_name|
|
80
|
+
next if !send(self.class.aasm(state_machine_name).attribute_name) || send(self.class.aasm(state_machine_name).attribute_name).empty?
|
81
|
+
send("#{self.class.aasm(state_machine_name).attribute_name}=", aasm(state_machine_name).enter_initial_state.to_s)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end # InstanceMethods
|
85
|
+
|
86
|
+
# module NamedScopeMethods
|
87
|
+
# def aasm_state_with_named_scope name, options = {}
|
88
|
+
# aasm_state_without_named_scope name, options
|
89
|
+
# self.named_scope name, :conditions => { "#{table_name}.#{self.aasm.attribute_name}" => name.to_s} unless self.respond_to?(name)
|
90
|
+
# end
|
91
|
+
# end
|
92
|
+
end
|
93
|
+
end # Persistence
|
94
|
+
end # AASM
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module AASM
|
2
|
+
module Persistence
|
3
|
+
module DynamoidPersistence
|
4
|
+
def self.included(base)
|
5
|
+
base.send(:include, AASM::Persistence::Base)
|
6
|
+
base.send(:include, AASM::Persistence::DynamoidPersistence::InstanceMethods)
|
7
|
+
|
8
|
+
base.after_initialize :aasm_ensure_initial_state
|
9
|
+
|
10
|
+
# Because Dynamoid only use define_method to add attribute assignment method in Class.
|
11
|
+
#
|
12
|
+
# In AASM::Base.initialize, it redefines and calls super in this method without superclass method.
|
13
|
+
# We override method_missing to solve this problem.
|
14
|
+
#
|
15
|
+
base.class_eval %Q(
|
16
|
+
def method_missing(method_name, *arguments, &block)
|
17
|
+
if (AASM::StateMachineStore.fetch(self.class, true).machine_names.map { |state_machine_name| self.class.aasm(state_machine_name).attribute_name.to_s + "=" }).include? method_name.to_s
|
18
|
+
attribute_name = method_name.to_s.gsub("=", '')
|
19
|
+
write_attribute(attribute_name.to_sym, *arguments)
|
20
|
+
else
|
21
|
+
super
|
22
|
+
end
|
23
|
+
end
|
24
|
+
)
|
25
|
+
end
|
26
|
+
|
27
|
+
module InstanceMethods
|
28
|
+
|
29
|
+
# Writes <tt>state</tt> to the state column and persists it to the database
|
30
|
+
# using update_attribute (which bypasses validation)
|
31
|
+
#
|
32
|
+
# foo = Foo.find(1)
|
33
|
+
# foo.aasm.current_state # => :opened
|
34
|
+
# foo.close!
|
35
|
+
# foo.aasm.current_state # => :closed
|
36
|
+
# Foo.find(1).aasm.current_state # => :closed
|
37
|
+
#
|
38
|
+
# NOTE: intended to be called from an event
|
39
|
+
def aasm_write_state(state, name=:default)
|
40
|
+
old_value = read_attribute(self.class.aasm(name).attribute_name)
|
41
|
+
write_attribute(self.class.aasm(name).attribute_name, state.to_s)
|
42
|
+
|
43
|
+
unless self.save(:validate => false)
|
44
|
+
write_attribute(self.class.aasm(name).attribute_name, old_value)
|
45
|
+
return false
|
46
|
+
end
|
47
|
+
|
48
|
+
true
|
49
|
+
end
|
50
|
+
|
51
|
+
# Writes <tt>state</tt> to the state column, but does not persist it to the database
|
52
|
+
#
|
53
|
+
# foo = Foo.find(1)
|
54
|
+
# foo.aasm.current_state # => :opened
|
55
|
+
# foo.close
|
56
|
+
# foo.aasm.current_state # => :closed
|
57
|
+
# Foo.find(1).aasm.current_state # => :opened
|
58
|
+
# foo.save
|
59
|
+
# foo.aasm.current_state # => :closed
|
60
|
+
# Foo.find(1).aasm.current_state # => :closed
|
61
|
+
#
|
62
|
+
# NOTE: intended to be called from an event
|
63
|
+
def aasm_write_state_without_persistence(state, name=:default)
|
64
|
+
write_attribute(self.class.aasm(name).attribute_name, state.to_s)
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
# Ensures that if the aasm_state column is nil and the record is new
|
70
|
+
# that the initial state gets populated before validation on create
|
71
|
+
#
|
72
|
+
# foo = Foo.new
|
73
|
+
# foo.aasm_state # => nil
|
74
|
+
# foo.valid?
|
75
|
+
# foo.aasm_state # => "open" (where :open is the initial state)
|
76
|
+
#
|
77
|
+
#
|
78
|
+
# foo = Foo.find(:first)
|
79
|
+
# foo.aasm_state # => 1
|
80
|
+
# foo.aasm_state = nil
|
81
|
+
# foo.valid?
|
82
|
+
# foo.aasm_state # => nil
|
83
|
+
#
|
84
|
+
def aasm_ensure_initial_state
|
85
|
+
AASM::StateMachineStore.fetch(self.class, true).machine_names.each do |state_machine_name|
|
86
|
+
aasm(state_machine_name).enter_initial_state if !send(self.class.aasm(state_machine_name).attribute_name) || send(self.class.aasm(state_machine_name).attribute_name).empty?
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end # InstanceMethods
|
90
|
+
end
|
91
|
+
end # Persistence
|
92
|
+
end # AASM
|
@@ -1,5 +1,4 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require 'aasm/persistence/orm'
|
3
2
|
module AASM
|
4
3
|
module Persistence
|
5
4
|
module MongoidPersistence
|
@@ -32,52 +31,58 @@ module AASM
|
|
32
31
|
#
|
33
32
|
def self.included(base)
|
34
33
|
base.send(:include, AASM::Persistence::Base)
|
34
|
+
base.send(:include, AASM::Persistence::ORM)
|
35
35
|
base.send(:include, AASM::Persistence::MongoidPersistence::InstanceMethods)
|
36
|
+
base.extend AASM::Persistence::MongoidPersistence::ClassMethods
|
36
37
|
|
37
38
|
base.after_initialize :aasm_ensure_initial_state
|
38
39
|
end
|
39
40
|
|
41
|
+
module ClassMethods
|
42
|
+
def aasm_create_scope(state_machine_name, scope_name)
|
43
|
+
scope_options = lambda {
|
44
|
+
send(
|
45
|
+
:where,
|
46
|
+
{ aasm(state_machine_name).attribute_name.to_sym => scope_name.to_s }
|
47
|
+
)
|
48
|
+
}
|
49
|
+
send(:scope, scope_name, scope_options)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
40
53
|
module InstanceMethods
|
41
54
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
# foo.close!
|
48
|
-
# foo.aasm.current_state # => :closed
|
49
|
-
# Foo.find(1).aasm.current_state # => :closed
|
50
|
-
#
|
51
|
-
# NOTE: intended to be called from an event
|
52
|
-
def aasm_write_state(state, name=:default)
|
53
|
-
old_value = read_attribute(self.class.aasm(name).attribute_name)
|
54
|
-
write_attribute(self.class.aasm(name).attribute_name, state.to_s)
|
55
|
+
private
|
56
|
+
|
57
|
+
def aasm_save
|
58
|
+
self.save
|
59
|
+
end
|
55
60
|
|
56
|
-
|
57
|
-
|
58
|
-
|
61
|
+
def aasm_raise_invalid_record
|
62
|
+
raise Mongoid::Errors::Validations.new(self)
|
63
|
+
end
|
64
|
+
|
65
|
+
def aasm_supports_transactions?
|
66
|
+
false
|
67
|
+
end
|
68
|
+
|
69
|
+
def aasm_update_column(attribute_name, value)
|
70
|
+
if Mongoid::VERSION.to_f >= 4
|
71
|
+
set(Hash[attribute_name, value])
|
72
|
+
else
|
73
|
+
set(attribute_name, value)
|
59
74
|
end
|
60
75
|
|
61
76
|
true
|
62
77
|
end
|
63
78
|
|
64
|
-
|
65
|
-
|
66
|
-
# foo = Foo.find(1)
|
67
|
-
# foo.aasm.current_state # => :opened
|
68
|
-
# foo.close
|
69
|
-
# foo.aasm.current_state # => :closed
|
70
|
-
# Foo.find(1).aasm.current_state # => :opened
|
71
|
-
# foo.save
|
72
|
-
# foo.aasm.current_state # => :closed
|
73
|
-
# Foo.find(1).aasm.current_state # => :closed
|
74
|
-
#
|
75
|
-
# NOTE: intended to be called from an event
|
76
|
-
def aasm_write_state_without_persistence(state, name=:default)
|
77
|
-
write_attribute(self.class.aasm(name).attribute_name, state.to_s)
|
79
|
+
def aasm_read_attribute(name)
|
80
|
+
read_attribute(name)
|
78
81
|
end
|
79
82
|
|
80
|
-
|
83
|
+
def aasm_write_attribute(name, value)
|
84
|
+
write_attribute(name, value)
|
85
|
+
end
|
81
86
|
|
82
87
|
# Ensures that if the aasm_state column is nil and the record is new
|
83
88
|
# that the initial state gets populated before validation on create
|
@@ -95,8 +100,17 @@ module AASM
|
|
95
100
|
# foo.aasm_state # => nil
|
96
101
|
#
|
97
102
|
def aasm_ensure_initial_state
|
98
|
-
AASM::
|
99
|
-
|
103
|
+
AASM::StateMachineStore.fetch(self.class, true).machine_names.each do |state_machine_name|
|
104
|
+
attribute_name = self.class.aasm(state_machine_name).attribute_name.to_s
|
105
|
+
# Do not load initial state when object attributes are not loaded,
|
106
|
+
# mongoid has_many relationship does not load child object attributes when
|
107
|
+
# only ids are loaded, for example parent.child_ids will not load child object attributes.
|
108
|
+
# This feature is introduced in mongoid > 4.
|
109
|
+
if attribute_names.include?(attribute_name) && !attributes[attribute_name] || attributes[attribute_name].empty?
|
110
|
+
# attribute_missing? is defined in mongoid > 4
|
111
|
+
return if Mongoid::VERSION.to_f >= 4 && attribute_missing?(attribute_name)
|
112
|
+
send("#{self.class.aasm(state_machine_name).attribute_name}=", aasm(state_machine_name).enter_initial_state.to_s)
|
113
|
+
end
|
100
114
|
end
|
101
115
|
end
|
102
116
|
end # InstanceMethods
|