simple_state_machine 0.5.2 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.github/workflows/build.yml +46 -0
- data/.gitignore +3 -0
- data/.travis.yml +17 -0
- data/Changelog.rdoc +16 -0
- data/Gemfile +7 -0
- data/README.rdoc +154 -99
- data/examples/conversation.rb +5 -5
- data/examples/lamp.rb +5 -5
- data/examples/relationship.rb +8 -8
- data/examples/traffic_light.rb +3 -3
- data/examples/user.rb +8 -4
- data/gemfiles/Gemfile.activerecord-5.2.x +9 -0
- data/gemfiles/Gemfile.activerecord-6.0.x +9 -0
- data/gemfiles/Gemfile.activerecord-6.1.x +8 -0
- data/gemfiles/Gemfile.activerecord-main.x +9 -0
- data/gemfiles/Gemfile.basic +6 -0
- data/lib/simple_state_machine/.DS_Store +0 -0
- data/lib/simple_state_machine/active_record.rb +2 -64
- data/lib/simple_state_machine/decorator/active_record.rb +68 -0
- data/lib/simple_state_machine/decorator/default.rb +91 -0
- data/lib/simple_state_machine/railtie.rb +1 -1
- data/lib/simple_state_machine/simple_state_machine.rb +8 -251
- data/lib/simple_state_machine/state_machine.rb +88 -0
- data/lib/simple_state_machine/state_machine_definition.rb +72 -0
- data/lib/simple_state_machine/tools/graphviz.rb +21 -0
- data/lib/simple_state_machine/tools/inspector.rb +44 -0
- data/lib/simple_state_machine/transition.rb +40 -0
- data/lib/simple_state_machine/version.rb +1 -1
- data/lib/simple_state_machine.rb +13 -3
- data/lib/tasks/graphviz.rake +31 -0
- data/simple_state_machine.gemspec +14 -24
- data/spec/.DS_Store +0 -0
- data/spec/active_record_spec.rb +216 -179
- data/spec/{decorator_spec.rb → decorator/default_spec.rb} +32 -32
- data/spec/examples_spec.rb +17 -17
- data/spec/mountable_spec.rb +26 -14
- data/spec/simple_state_machine_spec.rb +128 -92
- data/spec/spec_helper.rb +18 -5
- data/spec/state_machine_definition_spec.rb +48 -34
- data/spec/state_machine_spec.rb +36 -2
- data/spec/tools/graphviz_spec.rb +30 -0
- data/spec/tools/inspector_spec.rb +70 -0
- metadata +54 -128
- data/autotest/discover.rb +0 -1
- data/lib/tasks/graphiz.rake +0 -13
- data/rails/graphiz.rake +0 -16
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4cf708bed33ca00037b1fbb2562b2a4c351666d82a4555b84078600b9e90ad03
|
4
|
+
data.tar.gz: 251e24c03f5c59313aec334045670ed024c2720630c188d17bfed1eced1827be
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 482b1ba0a9e91260dfe56153453b636640dcd7c37916fd692e13d8607f59ee141d7161c9db6e9a50cdbb14b21b2895227129edf1c4f35dbcb733caceafeb8beb
|
7
|
+
data.tar.gz: 5c3b05eb49e792a4289e85c5be1f10f9239020a0147e0ab5b617bba58d7fac4b727a47f45564c472e25e4079e8d1fb7d52838f9a8af9dd610a90e2580d6a9132
|
@@ -0,0 +1,46 @@
|
|
1
|
+
name: Build
|
2
|
+
on:
|
3
|
+
- push
|
4
|
+
- pull_request
|
5
|
+
|
6
|
+
jobs:
|
7
|
+
build:
|
8
|
+
name: Ruby ${{ matrix.ruby }} / Rails ${{ matrix.rails }}
|
9
|
+
if: github.event_name == 'push' || github.event.pull_request.head.repo.full_name != github.repository
|
10
|
+
strategy:
|
11
|
+
fail-fast: false
|
12
|
+
matrix:
|
13
|
+
ruby:
|
14
|
+
- "3.0"
|
15
|
+
- "2.7"
|
16
|
+
- "2.6"
|
17
|
+
- "2.5"
|
18
|
+
rails:
|
19
|
+
- "5.2"
|
20
|
+
- "6.0"
|
21
|
+
- "6.1"
|
22
|
+
- main
|
23
|
+
exclude:
|
24
|
+
- ruby: 2.5
|
25
|
+
rails: main
|
26
|
+
- ruby: 2.6
|
27
|
+
rails: main
|
28
|
+
- ruby: 3.0
|
29
|
+
rails: "5.1"
|
30
|
+
- ruby: 3.0
|
31
|
+
rails: "5.2"
|
32
|
+
|
33
|
+
runs-on: 'ubuntu-latest'
|
34
|
+
|
35
|
+
env:
|
36
|
+
BUNDLE_GEMFILE: gemfiles/Gemfile.activerecord-${{ matrix.rails }}.x
|
37
|
+
|
38
|
+
steps:
|
39
|
+
- uses: actions/checkout@v2
|
40
|
+
- uses: ruby/setup-ruby@v1
|
41
|
+
with:
|
42
|
+
ruby-version: ${{ matrix.ruby }}
|
43
|
+
- name: Setup project
|
44
|
+
run: bundle install
|
45
|
+
- name: Run test
|
46
|
+
run: bundle exec rspec spec
|
data/.gitignore
CHANGED
data/.travis.yml
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
language: ruby
|
2
|
+
rvm:
|
3
|
+
- 2.5
|
4
|
+
- 2.7
|
5
|
+
- 3.0
|
6
|
+
- jruby-9.2.16.0
|
7
|
+
script: bundle exec rspec spec
|
8
|
+
|
9
|
+
gemfile:
|
10
|
+
- gemfiles/Gemfile.activerecord-6.0.x
|
11
|
+
- gemfiles/Gemfile.activerecord-6.1.x
|
12
|
+
- gemfiles/Gemfile.basic
|
13
|
+
|
14
|
+
matrix:
|
15
|
+
exclude:
|
16
|
+
- rvm: jruby
|
17
|
+
gemfile: gemfiles/Gemfile.activerecord-4.2.x
|
data/Changelog.rdoc
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
== 0.6.0
|
2
|
+
=== Enhancements
|
3
|
+
- Define decorated methods as #{event_name}_with_managed_state instead of with_managed_state_#{event_name} [Petrik]
|
4
|
+
- Added raised_error method to access caught Errors [Petrik]
|
5
|
+
- Added support for a default error state [Marek de Heus]
|
6
|
+
- Removed transaction support, you can still add it manually, see active_record_spec.rb [Marek de Heus]
|
7
|
+
- Allow catching errors for subclasses of the error [Petrik]
|
8
|
+
- Added gem install instructions [Marek de Heus]
|
9
|
+
- Added define_event method to simplify mountable state machine definitions [Petrik]
|
10
|
+
- Added end_states method so we can check the state machine correctness [Petrik]
|
11
|
+
- Added begin_states method so we can check the state machine correctness [Petrik]
|
12
|
+
|
13
|
+
=== Bugfixes
|
14
|
+
- Fixed bug in Inspector, from state can now be a Error class [Marek de Heus]
|
15
|
+
- Make sure from and end states are uniq [Petrik]
|
16
|
+
- fixed typos (graphiz -> graphviz) (redmar-master) [rjk]
|
data/Gemfile
CHANGED
data/README.rdoc
CHANGED
@@ -1,43 +1,29 @@
|
|
1
1
|
= SimpleStateMachine
|
2
2
|
|
3
|
+
{<img src="https://github.com/mdh/ssm/actions/workflows/build.yml/badge.svg" />}[https://github.com/mdh/ssm/actions?query=workflow%3A.github%2Fworkflows%2Fbuild.yml+branch%3Amaster++]
|
4
|
+
|
3
5
|
A simple DSL to decorate existing methods with state transition guards.
|
4
6
|
|
5
7
|
Instead of using a DSL to define events, SimpleStateMachine decorates methods
|
6
8
|
to help you encapsulate state and guard state transitions.
|
7
9
|
|
8
|
-
It supports exception rescuing, google chart visualization and mountable
|
9
|
-
|
10
|
-
== Basic example
|
11
|
-
|
12
|
-
class LampSwitch
|
13
|
-
|
14
|
-
extend SimpleStateMachine
|
10
|
+
It supports exception rescuing, google chart visualization and mountable state machines.
|
15
11
|
|
16
|
-
|
17
|
-
self.state = 'off'
|
18
|
-
end
|
12
|
+
== Usage
|
19
13
|
|
20
|
-
|
21
|
-
|
22
|
-
end
|
23
|
-
event :push_switch, :off => :on,
|
24
|
-
:on => :off
|
14
|
+
Define an event and specify how the state should transition. If we want the state to change
|
15
|
+
from *pending* to *active* we write:
|
25
16
|
|
26
|
-
|
27
|
-
|
28
|
-
lamp = LampSwitch.new
|
29
|
-
lamp.state # => 'off'
|
30
|
-
lamp.off? # => true
|
31
|
-
lamp.push_switch # => 'pushed switch'
|
32
|
-
lamp.state # => 'on'
|
33
|
-
lamp.on? # => true
|
34
|
-
lamp.push_switch # => 'pushed switch'
|
35
|
-
lamp.off? # => true
|
17
|
+
event :activate_account, :pending => :active
|
36
18
|
|
19
|
+
That's it. You can now call *activate_account* and the state will automatically change.
|
20
|
+
If the state change is not allowed, a SimpleStateMachine::IllegalStateTransitionError is
|
21
|
+
raised.
|
37
22
|
|
38
|
-
|
23
|
+
=== Methods with arguments
|
39
24
|
|
40
|
-
|
25
|
+
If you want to pass arguments and call other methods before the state transition, define your
|
26
|
+
event as a method.
|
41
27
|
|
42
28
|
def activate_account(activation_code)
|
43
29
|
# call other methods, no need to add these in callbacks
|
@@ -45,119 +31,187 @@ Define your event as a method, arguments are allowed:
|
|
45
31
|
end
|
46
32
|
|
47
33
|
Now mark the method as an event and specify how the state should transition
|
48
|
-
when the method is called.
|
34
|
+
when the method is called.
|
49
35
|
|
50
36
|
event :activate_account, :pending => :active
|
51
37
|
|
52
|
-
That's it!
|
53
|
-
You can now call activate_account and the state will automatically change.
|
54
|
-
If the state change is not allowed, a SimpleStateMachine::IllegalStateTransitionError is raised.
|
55
38
|
|
56
|
-
=== Using ActiveRecord / ActiveModel validations
|
57
|
-
When using ActiveRecord / ActiveModel you can add an error to the errors object.
|
58
|
-
This will prevent the state from being changed.
|
59
|
-
|
60
|
-
def activate_account(activation_code)
|
61
|
-
if activation_code_invalid?(activation_code)
|
62
|
-
errors.add(:activation_code, 'Invalid')
|
63
|
-
end
|
64
|
-
end
|
65
39
|
|
66
|
-
|
40
|
+
== Basic example
|
67
41
|
|
68
|
-
|
69
|
-
|
42
|
+
class LampSwitch
|
43
|
+
|
44
|
+
extend SimpleStateMachine
|
45
|
+
|
46
|
+
def initialize
|
47
|
+
self.state = 'off'
|
48
|
+
end
|
49
|
+
|
50
|
+
event :push_switch, :off => :on,
|
51
|
+
:on => :off
|
70
52
|
|
71
|
-
def download_data
|
72
|
-
Service.download_data
|
73
53
|
end
|
74
|
-
event :download_data, :pending => :downloaded,
|
75
|
-
Service::ConnectionError => :download_failed
|
76
54
|
|
77
|
-
|
78
|
-
state # =>
|
55
|
+
lamp = LampSwitch.new
|
56
|
+
lamp.state # => 'off'
|
57
|
+
lamp.off? # => true
|
58
|
+
lamp.push_switch #
|
59
|
+
lamp.state # => 'on'
|
60
|
+
lamp.on? # => true
|
61
|
+
lamp.push_switch #
|
62
|
+
lamp.off? # => true
|
79
63
|
|
80
|
-
=== Catching all from states
|
81
|
-
If an event should transition from all states you can use :all
|
82
64
|
|
83
|
-
|
65
|
+
== ActiveRecord
|
84
66
|
|
85
|
-
|
67
|
+
For ActiveRecord methods are decorated with state transition guards _and_ persistence.
|
68
|
+
Methods marked as events behave like ActiveRecord *save* and *save!*.
|
86
69
|
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
70
|
+
=== Example
|
71
|
+
|
72
|
+
To add a state machine to an ActiveRecord class, you will have to:
|
73
|
+
* extend SimpleStateMachine::ActiveRecord,
|
74
|
+
* set the initial state in after_initialize,
|
75
|
+
* turn methods into events
|
91
76
|
|
92
77
|
class User < ActiveRecord::Base
|
93
|
-
|
78
|
+
|
94
79
|
extend SimpleStateMachine::ActiveRecord
|
95
80
|
|
96
|
-
|
97
|
-
self.
|
98
|
-
# if you get an ActiveRecord::MissingAttributeError
|
99
|
-
# you'll probably need to do (http://bit.ly/35q23b):
|
100
|
-
# write_attribute(:ssm_state, "pending") unless read_attribute(:ssm_state)
|
81
|
+
after_initialize do
|
82
|
+
self.state ||= 'pending'
|
101
83
|
end
|
102
|
-
|
84
|
+
|
103
85
|
def invite
|
104
86
|
self.activation_code = Digest::SHA1.hexdigest("salt #{Time.now.to_f}")
|
105
|
-
#send_activation_email
|
106
87
|
end
|
107
88
|
event :invite, :pending => :invited
|
108
|
-
|
109
|
-
def confirm_invitation activation_code
|
110
|
-
if self.activation_code != activation_code
|
111
|
-
errors.add 'activation_code', 'is invalid'
|
112
|
-
end
|
113
|
-
end
|
114
|
-
event :confirm_invitation, :invited => :active
|
115
89
|
end
|
116
90
|
|
117
|
-
|
118
|
-
|
119
|
-
|
91
|
+
user = User.new
|
92
|
+
user.pending? # => true
|
93
|
+
user.invite # => true
|
94
|
+
user.invited? # => true
|
95
|
+
user.activation_code # => 'SOMEDIGEST'
|
120
96
|
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
- active?
|
97
|
+
For the invite method this generates the following event methods
|
98
|
+
* *invite* (behaves like ActiveRecord save )
|
99
|
+
* *invite!* (behaves like ActiveRecord save!)
|
125
100
|
|
126
101
|
If you want to be more verbose you can also use:
|
127
|
-
|
128
|
-
|
102
|
+
* *invite_and_save* (alias for invite)
|
103
|
+
* *invite_and_save!* (alias for invite!)
|
129
104
|
|
130
|
-
== Mountable Example
|
131
105
|
|
132
|
-
|
106
|
+
=== Using ActiveRecord / ActiveModel validations
|
107
|
+
|
108
|
+
When using ActiveRecord / ActiveModel you can add an error to the errors object.
|
109
|
+
This will prevent the state from being changed.
|
110
|
+
|
111
|
+
If we add an activate_account method to User
|
133
112
|
|
134
|
-
class
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
113
|
+
class User < ActiveRecord::Base
|
114
|
+
...
|
115
|
+
def activate_account(activation_code)
|
116
|
+
if activation_code_invalid?(activation_code)
|
117
|
+
errors.add(:activation_code, 'Invalid')
|
118
|
+
end
|
139
119
|
end
|
120
|
+
event :activate_account, :invited => :confirmed
|
121
|
+
...
|
140
122
|
end
|
141
123
|
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
124
|
+
user.confirm_invitation!('INVALID') # => raises ActiveRecord::RecordInvalid,
|
125
|
+
# "Validation failed: Activation code is invalid"
|
126
|
+
user.confirmed? # => false
|
127
|
+
user.confirm_invitation!('VALID')
|
128
|
+
user.confirmed? # => true
|
146
129
|
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
130
|
+
== Mountable StateMachines
|
131
|
+
|
132
|
+
If you like to separate your state machine from your model class, you can do so as following:
|
133
|
+
|
134
|
+
class MyStateMachine < SimpleStateMachine::StateMachineDefinition
|
135
|
+
|
136
|
+
event :invite, :new => :invited
|
137
|
+
event :confirm_invitation, :invited => :active
|
138
|
+
|
139
|
+
def decorator_class
|
140
|
+
SimpleStateMachine::Decorator::Default
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
class User < ActiveRecord::Base
|
145
|
+
|
146
|
+
extend SimpleStateMachine::Mountable
|
147
|
+
mount_state_machine MyStateMachine
|
148
|
+
|
149
|
+
after_initialize do
|
150
|
+
self.state ||= 'new'
|
151
151
|
end
|
152
152
|
|
153
|
+
end
|
154
|
+
|
153
155
|
|
154
|
-
==
|
156
|
+
== Transitions
|
155
157
|
|
156
|
-
|
158
|
+
=== Catching all from states
|
159
|
+
If an event should transition from all other defined states, you can use the *:all* state:
|
160
|
+
|
161
|
+
event :suspend, :all => :suspended
|
162
|
+
|
163
|
+
|
164
|
+
=== Catching exceptions
|
165
|
+
|
166
|
+
You can let the state machine handle exceptions by specifying the failure state for an Error:
|
167
|
+
|
168
|
+
def download_data
|
169
|
+
raise Service::ConnectionError, "Uhoh"
|
170
|
+
end
|
171
|
+
event :download_data, Service::ConnectionError => :download_failed
|
157
172
|
|
173
|
+
download_data # catches Service::ConnectionError
|
174
|
+
state # => "download_failed"
|
175
|
+
state_machine.raised_error # "Uhoh"
|
176
|
+
|
177
|
+
|
178
|
+
=== Default error state
|
179
|
+
|
180
|
+
To automatically catch all exceptions to a default error state use default_error_state:
|
181
|
+
|
182
|
+
state_machine_definition.default_error_state = :failed
|
183
|
+
|
184
|
+
== Transactions
|
185
|
+
|
186
|
+
If you want to run events in transactions run them in a transaction block:
|
187
|
+
|
188
|
+
user.transaction { user.invite! }
|
189
|
+
|
190
|
+
== Tools
|
191
|
+
|
192
|
+
===Generating state diagrams
|
193
|
+
|
194
|
+
When using Rails/ActiveRecord you can generate a state diagram of the state machine via the
|
195
|
+
built in rake tasks.
|
196
|
+
For details run:
|
197
|
+
|
198
|
+
rake -T ssm
|
199
|
+
|
200
|
+
A Googlechart example:
|
201
|
+
http://tinyurl.com/79xztr6
|
202
|
+
|
203
|
+
== Installation
|
204
|
+
|
205
|
+
Use gem install:
|
206
|
+
|
207
|
+
gem install simple_state_machine
|
208
|
+
|
209
|
+
Or add it to your Gemfile:
|
210
|
+
|
211
|
+
gem 'simple_state_machine'
|
158
212
|
|
159
213
|
== Note on Patches/Pull Requests
|
160
|
-
|
214
|
+
|
161
215
|
* Fork the project.
|
162
216
|
* Make your feature addition or bug fix.
|
163
217
|
* Add tests for it. This is important so I don't break it in a
|
@@ -166,6 +220,7 @@ If your using rails you get rake tasks for generating a graphiz google chart of
|
|
166
220
|
(if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
167
221
|
* Send me a pull request. Bonus points for topic branches.
|
168
222
|
|
223
|
+
|
169
224
|
== Copyright
|
170
225
|
|
171
226
|
Copyright (c) 2010 Marek & Petrik. See LICENSE for details.
|
data/examples/conversation.rb
CHANGED
@@ -2,19 +2,19 @@
|
|
2
2
|
#
|
3
3
|
# class Conversation
|
4
4
|
# include AASM
|
5
|
-
#
|
5
|
+
#
|
6
6
|
# aasm_column :current_state # defaults to aasm_state
|
7
|
-
#
|
7
|
+
#
|
8
8
|
# aasm_initial_state :unread
|
9
|
-
#
|
9
|
+
#
|
10
10
|
# aasm_state :unread
|
11
11
|
# aasm_state :read
|
12
12
|
# aasm_state :closed
|
13
|
-
#
|
13
|
+
#
|
14
14
|
# aasm_event :view do
|
15
15
|
# transitions :to => :read, :from => [:unread]
|
16
16
|
# end
|
17
|
-
#
|
17
|
+
#
|
18
18
|
# aasm_event :close do
|
19
19
|
# transitions :to => :closed, :from => [:read, :unread]
|
20
20
|
# end
|
data/examples/lamp.rb
CHANGED
@@ -1,21 +1,21 @@
|
|
1
1
|
class Lamp
|
2
|
-
|
2
|
+
|
3
3
|
extend SimpleStateMachine
|
4
4
|
|
5
5
|
def initialize
|
6
6
|
self.state = 'off'
|
7
7
|
end
|
8
|
-
|
8
|
+
|
9
9
|
def push_button1
|
10
10
|
puts "click1: #{state}"
|
11
11
|
end
|
12
|
-
event :push_button1, :off => :on,
|
12
|
+
event :push_button1, :off => :on,
|
13
13
|
:on => :off
|
14
|
-
|
14
|
+
|
15
15
|
def push_button2
|
16
16
|
puts "click2: #{state}"
|
17
17
|
end
|
18
18
|
event :push_button2, :off => :on,
|
19
19
|
:on => :off
|
20
20
|
|
21
|
-
end
|
21
|
+
end
|
data/examples/relationship.rb
CHANGED
@@ -2,23 +2,23 @@
|
|
2
2
|
#
|
3
3
|
# class Relationship
|
4
4
|
# include AASM
|
5
|
-
#
|
5
|
+
#
|
6
6
|
# aasm_column :status
|
7
|
-
#
|
7
|
+
#
|
8
8
|
# aasm_initial_state Proc.new { |relationship| relationship.strictly_for_fun? ? :intimate : :dating }
|
9
|
-
#
|
9
|
+
#
|
10
10
|
# aasm_state :dating, :enter => :make_happy, :exit => :make_depressed
|
11
11
|
# aasm_state :intimate, :enter => :make_very_happy, :exit => :never_speak_again
|
12
12
|
# aasm_state :married, :enter => :give_up_intimacy, :exit => :buy_exotic_car_and_wear_a_combover
|
13
|
-
#
|
13
|
+
#
|
14
14
|
# aasm_event :get_intimate do
|
15
15
|
# transitions :to => :intimate, :from => [:dating], :guard => :drunk?
|
16
16
|
# end
|
17
|
-
#
|
17
|
+
#
|
18
18
|
# aasm_event :get_married do
|
19
19
|
# transitions :to => :married, :from => [:dating, :intimate], :guard => :willing_to_give_up_manhood?
|
20
20
|
# end
|
21
|
-
#
|
21
|
+
#
|
22
22
|
# def strictly_for_fun?; end
|
23
23
|
# def drunk?; end
|
24
24
|
# def willing_to_give_up_manhood?; end
|
@@ -32,7 +32,7 @@
|
|
32
32
|
|
33
33
|
class Relationship
|
34
34
|
extend SimpleStateMachine
|
35
|
-
|
35
|
+
|
36
36
|
def initialize
|
37
37
|
self.state = relationship.strictly_for_fun? ? get_intimate : start_dating
|
38
38
|
end
|
@@ -84,4 +84,4 @@ class Relationship
|
|
84
84
|
def never_speak_again; end
|
85
85
|
def give_up_intimacy; end
|
86
86
|
def buy_exotic_car_and_wear_a_combover; end
|
87
|
-
end
|
87
|
+
end
|
data/examples/traffic_light.rb
CHANGED
data/examples/user.rb
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
require 'digest/sha1'
|
2
2
|
class User < ActiveRecord::Base
|
3
|
-
|
3
|
+
|
4
4
|
validates_presence_of :name
|
5
|
-
|
5
|
+
|
6
6
|
extend SimpleStateMachine::ActiveRecord
|
7
7
|
|
8
|
+
after_initialize :after_initialize
|
8
9
|
def after_initialize
|
9
10
|
self.state ||= 'new'
|
11
|
+
# if you get an ActiveRecord::MissingAttributeError
|
12
|
+
# you'll probably need to do (http://bit.ly/35q23b):
|
13
|
+
# write_attribute(:ssm_state, "pending") unless read_attribute(:ssm_state)
|
10
14
|
end
|
11
15
|
|
12
16
|
def invite
|
@@ -23,13 +27,13 @@ class User < ActiveRecord::Base
|
|
23
27
|
event :confirm_invitation, :invited => :active
|
24
28
|
|
25
29
|
#event :log_send_activation_code_failed, :new => :send_activation_code_failed
|
26
|
-
#
|
30
|
+
#
|
27
31
|
# def reset_password(new_password)
|
28
32
|
# self.password = new_password
|
29
33
|
# end
|
30
34
|
# # do not change state, but ensure that we are in proper state
|
31
35
|
# event :reset_password, :active => :active
|
32
|
-
|
36
|
+
|
33
37
|
def send_activation_email(code)
|
34
38
|
true
|
35
39
|
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
# A sample Gemfile
|
2
|
+
source "http://rubygems.org"
|
3
|
+
|
4
|
+
group :test do
|
5
|
+
gem "rspec"
|
6
|
+
gem "activerecord", git: "https://github.com/rails/rails.git", branch: "main"
|
7
|
+
gem "sqlite3", :platform => [:ruby, :mswin, :mingw]
|
8
|
+
gem "activerecord-jdbcsqlite3-adapter", :platform => :jruby
|
9
|
+
end
|
Binary file
|