has_state_machine 0.3.3 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 524c408a87a46086495361e76507c6d1eb963acc6d72664c3faf0c8c913fa19f
4
- data.tar.gz: 992299b87230582800a63afdf47bd573003481f74e3d521de414d8e20c783bf4
3
+ metadata.gz: 58bd21a655ff20122628fbc9707b04d77be5a318753cabb721c16073ad9d7edb
4
+ data.tar.gz: ee6c83c9b070867c9715b9dc3970597f9c5db61ae616839f2bd3841bd397b501
5
5
  SHA512:
6
- metadata.gz: a49dd7b572ba738ce5c29db2bb9f50100595a47353aa28b8bfb0e814340381202ac2db180efd42dfe9aea691088170eaf7ea266b1da0fc3a4d30ca287c266e44
7
- data.tar.gz: 4a6ab1dfca389dcd4eac9d05a826d28cdbe145329dc078370327e76a07a2c8993d5fb470d981717ebec58c70c811501e447d20931d7cee0af8e8109132af6e41
6
+ metadata.gz: ce2c67a3440e3175693e589188456434ac593c3f219abcdb9607f7f2241a00e51746764c5b17623c66259f9bc6fdb3e1de8547262da27c93d16adefdf090b130
7
+ data.tar.gz: da2d558bc3dbd3686ce46538bd426956c5664a3f608350007643ae53626eae944f95c5d6180ca42b39459006bbd4084faf7b58d1a6354d262119d64718f16eac
data/README.md CHANGED
@@ -7,13 +7,16 @@ HasStateMachine uses ruby classes to make creating a finite state machine for yo
7
7
 
8
8
  ## Contents
9
9
 
10
- - [Installation](#installation)
11
- - [Usage](#usage)
12
- - [Changelog](https://github.com/encampment/has_state_machine/blob/master/CHANGELOG.md)
13
- - [Contributing](#contributing)
14
- - [License](#license)
10
+ - [HasStateMachine](#hasstatemachine)
11
+ - [Contents](#contents)
12
+ - [Installation](#installation)
13
+ - [Usage](#usage)
14
+ - [Advanced Usage](#advanced-usage)
15
+ - [Contributing](#contributing)
16
+ - [License](#license)
15
17
 
16
18
  ## Installation
19
+
17
20
  Add this line to your application's Gemfile:
18
21
 
19
22
  ```ruby
@@ -21,11 +24,13 @@ gem 'has_state_machine'
21
24
  ```
22
25
 
23
26
  And then execute:
27
+
24
28
  ```bash
25
29
  $ bundle
26
30
  ```
27
31
 
28
32
  Or install it yourself as:
33
+
29
34
  ```bash
30
35
  $ gem install has_state_machine
31
36
  ```
@@ -36,6 +41,7 @@ You must first use the `has_state_machine` macro to define your state machine at
36
41
  a high level. This includes defining the possible states for your object as well
37
42
  as some optional configuration should you want to change the default behavior of
38
43
  the state machine.
44
+
39
45
  ```ruby
40
46
  # By default, it is assumed that the "state" of the object is
41
47
  # stored in a string column named "status".
@@ -53,13 +59,13 @@ from `HasStateMachine::State`.
53
59
  module Workflow
54
60
  class Post::Draft < HasStateMachine::State
55
61
  # Define the possible transitions from the "draft" state
56
- transitions_to %i[published archived]
62
+ state_options transitions_to: %i[published archived]
57
63
  end
58
64
  end
59
65
 
60
66
  module Workflow
61
67
  class Post::Published < HasStateMachine::State
62
- transitions_to %i[archived]
68
+ state_options transitions_to: %i[archived]
63
69
 
64
70
  # Custom validations can be added to the state to ensure a transition is "valid"
65
71
  validate :title_exists?
@@ -111,6 +117,28 @@ post.status.transition_to(:archived)
111
117
  # => true
112
118
  ```
113
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
140
+ ```
141
+
114
142
  ## Contributing
115
143
 
116
144
  Anyone is encouraged to help improve this project. Here are a few ways you can help:
@@ -130,4 +158,5 @@ bundle exec rake test
130
158
  ```
131
159
 
132
160
  ## License
161
+
133
162
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
@@ -36,28 +36,28 @@ module HasStateMachine
36
36
  def define_helper_methods(states:, options:)
37
37
  ##
38
38
  # The list of possible states in the state machine.
39
- define_singleton_method "workflow_states" do
39
+ define_singleton_method :workflow_states do
40
40
  states
41
41
  end
42
42
 
43
43
  ##
44
44
  # Defines the column name for the attribute holding the current status.
45
45
  # Can be overwritten to use a different column name.
46
- define_singleton_method "state_attribute" do
46
+ define_singleton_method :state_attribute do
47
47
  options[:state_attribute]&.to_sym || :status
48
48
  end
49
49
 
50
50
  ##
51
51
  # Defines the namespace of the models possible states.
52
52
  # Can be overwritten to use a different namespace.
53
- define_singleton_method "workflow_namespace" do
53
+ define_singleton_method :workflow_namespace do
54
54
  (options[:workflow_namespace] || "Workflow::#{self}")
55
55
  end
56
56
 
57
57
  ##
58
58
  # Determines whether or not the state validations should be run
59
59
  # as part of the object validations; they are by default.
60
- define_singleton_method "state_validations_on_object?" do
60
+ define_singleton_method :state_validations_on_object? do
61
61
  return true unless options.key?(:state_validations_on_object)
62
62
 
63
63
  options[:state_validations_on_object]
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/deprecation"
4
+
5
+ module HasStateMachine
6
+ Deprecation = ActiveSupport::Deprecation.new("1.0", "HasStateMachine")
7
+ end
@@ -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
- delegate :possible_transitions, :state, to: "self.class"
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
- transitioned = state_instance(desired_state.to_s).perform_transition!
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
- @possible_transitions = states.map(&:to_s)
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
@@ -56,7 +56,7 @@ module HasStateMachine
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) }
59
+ scope state, -> { where("#{table_name}.#{state_attribute} = ?", state) }
60
60
  end
61
61
 
62
62
  ##
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module HasStateMachine
4
- VERSION = "0.3.3"
4
+ VERSION = "0.4.1"
5
5
  end
@@ -3,6 +3,7 @@
3
3
  require "has_state_machine/railtie"
4
4
  require "has_state_machine/core_ext/string"
5
5
  require "has_state_machine/definition"
6
+ require "has_state_machine/deprecation"
6
7
 
7
8
  module HasStateMachine
8
9
  end
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.3.3
4
+ version: 0.4.1
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: 2021-01-22 00:00:00.000000000 Z
12
+ date: 2023-03-02 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
@@ -133,7 +134,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
133
134
  - !ruby/object:Gem::Version
134
135
  version: '0'
135
136
  requirements: []
136
- rubygems_version: 3.1.4
137
+ rubygems_version: 3.1.6
137
138
  signing_key:
138
139
  specification_version: 4
139
140
  summary: Class based state machine for ActiveRecord models.