has_state_machine 0.2.0 → 0.4.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 +4 -4
- data/README.md +64 -6
- data/lib/has_state_machine.rb +1 -0
- data/lib/has_state_machine/deprecation.rb +7 -0
- data/lib/has_state_machine/state.rb +41 -4
- data/lib/has_state_machine/state_helpers.rb +4 -2
- data/lib/has_state_machine/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: eb504bbd9b6e978b3a62551273a74624cdb4d189545cb32bf45a7f060983e888
|
4
|
+
data.tar.gz: ac89964cd89cec827ac60c8fae3970d94329c0141c0078da7a409ff2f63547ff
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e62938a674ba7e8bea155e536724220280458a32bfa4dc3bdeed402bba4067a54b253b76f017fec7a25b361e349b92d88daf00d8071464bc72814f96e1ae152d
|
7
|
+
data.tar.gz: cfc4cf9a5b21dc548cc4207979ac1325e5134dfe6d4fd3114ca6d623ac22ca8afcdc899cfea192030986f7ab42268405ebd6edc7201fab976752d9d6447879f9
|
data/README.md
CHANGED
@@ -5,7 +5,18 @@
|
|
5
5
|
|
6
6
|
HasStateMachine uses ruby classes to make creating a finite state machine for your ActiveRecord models a breeze.
|
7
7
|
|
8
|
+
## Contents
|
9
|
+
|
10
|
+
- [HasStateMachine](#hasstatemachine)
|
11
|
+
- [Contents](#contents)
|
12
|
+
- [Installation](#installation)
|
13
|
+
- [Usage](#usage)
|
14
|
+
- [Advanced Usage](#advanced-usage)
|
15
|
+
- [Contributing](#contributing)
|
16
|
+
- [License](#license)
|
17
|
+
|
8
18
|
## Installation
|
19
|
+
|
9
20
|
Add this line to your application's Gemfile:
|
10
21
|
|
11
22
|
```ruby
|
@@ -13,11 +24,13 @@ gem 'has_state_machine'
|
|
13
24
|
```
|
14
25
|
|
15
26
|
And then execute:
|
27
|
+
|
16
28
|
```bash
|
17
29
|
$ bundle
|
18
30
|
```
|
19
31
|
|
20
32
|
Or install it yourself as:
|
33
|
+
|
21
34
|
```bash
|
22
35
|
$ gem install has_state_machine
|
23
36
|
```
|
@@ -28,6 +41,7 @@ You must first use the `has_state_machine` macro to define your state machine at
|
|
28
41
|
a high level. This includes defining the possible states for your object as well
|
29
42
|
as some optional configuration should you want to change the default behavior of
|
30
43
|
the state machine.
|
44
|
+
|
31
45
|
```ruby
|
32
46
|
# By default, it is assumed that the "state" of the object is
|
33
47
|
# stored in a string column named "status".
|
@@ -45,13 +59,13 @@ from `HasStateMachine::State`.
|
|
45
59
|
module Workflow
|
46
60
|
class Post::Draft < HasStateMachine::State
|
47
61
|
# Define the possible transitions from the "draft" state
|
48
|
-
transitions_to %i[published archived]
|
62
|
+
state_options transitions_to: %i[published archived]
|
49
63
|
end
|
50
64
|
end
|
51
65
|
|
52
66
|
module Workflow
|
53
67
|
class Post::Published < HasStateMachine::State
|
54
|
-
transitions_to %i[archived]
|
68
|
+
state_options transitions_to: %i[archived]
|
55
69
|
|
56
70
|
# Custom validations can be added to the state to ensure a transition is "valid"
|
57
71
|
validate :title_exists?
|
@@ -70,15 +84,15 @@ module Workflow
|
|
70
84
|
# There are callbacks for running logic before and after
|
71
85
|
# a transition occurs.
|
72
86
|
before_transition do
|
73
|
-
Rails.logger.info "Post is being archived
|
87
|
+
Rails.logger.info "== Post is being archived ==\n"
|
74
88
|
end
|
75
89
|
|
76
90
|
after_transition do
|
77
|
-
Rails.logger.info "Post has been archived
|
91
|
+
Rails.logger.info "== Post has been archived ==\n"
|
78
92
|
|
79
93
|
# You can access the previous state of the object in
|
80
94
|
# after_transition callbacks as well.
|
81
|
-
Rails.logger.info "Transitioned from #{previous_state}
|
95
|
+
Rails.logger.info "== Transitioned from #{previous_state} ==\n"
|
82
96
|
end
|
83
97
|
end
|
84
98
|
end
|
@@ -95,10 +109,54 @@ post.status # => "draft"
|
|
95
109
|
post.title = "Foobar"
|
96
110
|
post.status.transition_to(:published) # => true
|
97
111
|
post.status # => "published"
|
112
|
+
|
113
|
+
post.status.transition_to(:archived)
|
114
|
+
# == Post is being archived ==
|
115
|
+
# == Post has been archived ==
|
116
|
+
# == Transitioned from published ==
|
117
|
+
# => true
|
118
|
+
```
|
119
|
+
|
120
|
+
### Advanced Usage
|
121
|
+
|
122
|
+
Sometimes there may be a situation where you want to manually roll back a state change in one of the provided callbacks. To do this, add the `transactional: true` option to the `state_options` declaration and use the `rollback_transition` method in your callback. This will allow you to prevent the transition from persisting if something further down the line fails.
|
123
|
+
|
124
|
+
```ruby
|
125
|
+
module Workflow
|
126
|
+
class Post::Archived < HasStateMachine::State
|
127
|
+
state_options transactional: true
|
128
|
+
|
129
|
+
after_transition do
|
130
|
+
rollback_transition unless notified_watchers?
|
131
|
+
end
|
132
|
+
|
133
|
+
private
|
134
|
+
|
135
|
+
def notified_watchers?
|
136
|
+
#...
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
98
140
|
```
|
99
141
|
|
100
142
|
## Contributing
|
101
|
-
|
143
|
+
|
144
|
+
Anyone is encouraged to help improve this project. Here are a few ways you can help:
|
145
|
+
|
146
|
+
- [Report bugs](https://github.com/encampment/has_state_machine/issues)
|
147
|
+
- Fix bugs and [submit pull requests](https://github.com/encampment/has_state_machine/pulls)
|
148
|
+
- Write, clarify, or fix documentation
|
149
|
+
- Suggest or add new features
|
150
|
+
|
151
|
+
To get started with development:
|
152
|
+
|
153
|
+
```
|
154
|
+
git clone https://github.com/encampment/has_state_machine.git
|
155
|
+
cd has_state_machine
|
156
|
+
bundle install
|
157
|
+
bundle exec rake test
|
158
|
+
```
|
102
159
|
|
103
160
|
## License
|
161
|
+
|
104
162
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/lib/has_state_machine.rb
CHANGED
@@ -16,8 +16,9 @@ module HasStateMachine
|
|
16
16
|
define_model_callbacks :transition, only: %i[before after]
|
17
17
|
|
18
18
|
##
|
19
|
-
# Retrieves the next available transitions for a given state.
|
20
|
-
|
19
|
+
# possible_transitions - Retrieves the next available transitions for a given state.
|
20
|
+
# transactional? - Determines whether or not the transition should happen with a transactional block.
|
21
|
+
delegate :possible_transitions, :transactional?, :state, to: "self.class"
|
21
22
|
|
22
23
|
##
|
23
24
|
# Add errors to the ActiveRecord object rather than the HasStateMachine::State
|
@@ -51,7 +52,13 @@ module HasStateMachine
|
|
51
52
|
with_transition_options(options) do
|
52
53
|
return false unless valid_transition?(desired_state.to_s)
|
53
54
|
|
54
|
-
|
55
|
+
desired_state = state_instance(desired_state.to_s)
|
56
|
+
|
57
|
+
transitioned = if desired_state.transactional?
|
58
|
+
desired_state.perform_transactional_transition!
|
59
|
+
else
|
60
|
+
desired_state.perform_transition!
|
61
|
+
end
|
55
62
|
end
|
56
63
|
|
57
64
|
transitioned
|
@@ -66,8 +73,24 @@ module HasStateMachine
|
|
66
73
|
end
|
67
74
|
end
|
68
75
|
|
76
|
+
##
|
77
|
+
# Makes the actual transition from one state to the next and
|
78
|
+
# runs the before and after transition callbacks in a transaction
|
79
|
+
# to allow for roll backs.
|
80
|
+
def perform_transactional_transition!
|
81
|
+
ActiveRecord::Base.transaction(requires_new: true, joinable: false) do
|
82
|
+
run_callbacks :transition do
|
83
|
+
rollback_transition unless object.update("#{object.state_attribute}": state)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
69
88
|
private
|
70
89
|
|
90
|
+
def rollback_transition
|
91
|
+
raise ActiveRecord::Rollback
|
92
|
+
end
|
93
|
+
|
71
94
|
##
|
72
95
|
# Determines if the given desired state exists in the predetermined
|
73
96
|
# list of allowed transitions.
|
@@ -111,11 +134,25 @@ module HasStateMachine
|
|
111
134
|
to_s.demodulize.underscore
|
112
135
|
end
|
113
136
|
|
137
|
+
def transactional?
|
138
|
+
@transactional || false
|
139
|
+
end
|
140
|
+
|
114
141
|
##
|
115
142
|
# Setter for the HasStateMachine::State classes to define the possible
|
116
143
|
# states the current state can transition to.
|
117
144
|
def transitions_to(states)
|
118
|
-
|
145
|
+
state_options(transitions_to: states)
|
146
|
+
HasStateMachine::Deprecation.deprecation_warning(:transitions_to, "use state_options instead")
|
147
|
+
end
|
148
|
+
|
149
|
+
##
|
150
|
+
# Set the options for the HasStateMachine::State classes to define the possible
|
151
|
+
# states the current state can transition to and whether or not transitioning
|
152
|
+
# to the state should be performed within a transaction.
|
153
|
+
def state_options(transitions_to: [], transactional: false)
|
154
|
+
@possible_transitions = transitions_to.map(&:to_s)
|
155
|
+
@transactional = transactional
|
119
156
|
end
|
120
157
|
end
|
121
158
|
end
|
@@ -55,7 +55,9 @@ module HasStateMachine
|
|
55
55
|
# @example Retreiving a users published posts
|
56
56
|
# > Post.published.where(user: user)
|
57
57
|
# #=> [#<Post>]
|
58
|
-
|
58
|
+
if defined?(ActiveRecord) && (self < ActiveRecord::Base)
|
59
|
+
scope state, -> { where("#{state_attribute} = ?", state) }
|
60
|
+
end
|
59
61
|
|
60
62
|
##
|
61
63
|
# Defines boolean helpers to determine if the active state matches
|
@@ -76,7 +78,7 @@ module HasStateMachine
|
|
76
78
|
# Getter for the current state of the model based on the configured state
|
77
79
|
# attribute.
|
78
80
|
def current_state
|
79
|
-
|
81
|
+
attributes.with_indifferent_access[state_attribute]
|
80
82
|
end
|
81
83
|
|
82
84
|
##
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: has_state_machine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Benjamin Hargett
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2021-04-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
@@ -110,6 +110,7 @@ files:
|
|
110
110
|
- lib/has_state_machine.rb
|
111
111
|
- lib/has_state_machine/core_ext/string.rb
|
112
112
|
- lib/has_state_machine/definition.rb
|
113
|
+
- lib/has_state_machine/deprecation.rb
|
113
114
|
- lib/has_state_machine/railtie.rb
|
114
115
|
- lib/has_state_machine/state.rb
|
115
116
|
- lib/has_state_machine/state_helpers.rb
|