state_machines-audit_trail 1.0.0 → 2.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: b8a0bfd2dd9a83185bc24c1c55d3804b2fba5a8e
4
- data.tar.gz: 03e55491819582dbf56a32b494756564d0da7ffd
2
+ SHA256:
3
+ metadata.gz: fa9c1aad624d9dad005c50ab44eb5522908b1790490f6e8b1eacc1b05261a7e3
4
+ data.tar.gz: 9bcb723941ab88d56534181ad6be0c147de7262ee408c2a5607a77bd146b94e2
5
5
  SHA512:
6
- metadata.gz: d1c764d8ed988ecb2a766939127e76ce902241320bd53fdce5641830bb3eb52c666179dae873d23fc2f989a5fd65013722af497716a59d65e06c5d5d5a659e6b
7
- data.tar.gz: 60d5d11f419b337f253141fb36a17a51dcb2852cb549e89b64a59f4c8f06ed8a30fe7785038138a7a11884212ca1cd0b52cbac094cd9133699eb3165a5dd39f4
6
+ metadata.gz: ffaacbb29036d844d7a25d72da512906bee8d7a646e63b42b68f3f99bfcd7ff572e33177b84cf85ef079cb284dc2667611ce22b40835d524f065fdfb76f7926f
7
+ data.tar.gz: 15cf000aea32b80c3f0cf675fe9cad34574ce127d4328c3faea9f70b62e7d35550b67ef62ed9209000bf46c84e949ccec27821ba2d90861cfb075c43ae616a76
data/.gitignore CHANGED
@@ -1,6 +1,7 @@
1
1
  *.gem
2
- /.bundle
2
+ .bundle
3
3
  Gemfile.lock
4
+ *.gemfile.lock
4
5
  pkg/*
5
6
  .DS_Store
6
7
  *.rbc
@@ -0,0 +1 @@
1
+ state_machines-audit_trail
@@ -0,0 +1 @@
1
+ 2.3.1
@@ -1,17 +1,43 @@
1
1
  language: ruby
2
- sudo: false
3
2
  cache: bundler
4
3
 
5
4
  script: "bundle exec rake"
6
5
 
7
6
  services: mongodb
8
7
  rvm:
9
- - 2.1
10
- - 2.0.0
11
8
  - 2.2
9
+ - 2.3
10
+ - 2.4
11
+ - 2.5
12
+ - 2.6
13
+ - 2.7
14
+ - ruby-head
15
+ - jruby-head
12
16
  - jruby
13
17
  - rbx-2
18
+ gemfile:
19
+ - gemfiles/rails_5.0.gemfile
20
+ - gemfiles/rails_5.1.gemfile
21
+ - gemfiles/rails_5.2.gemfile
22
+ - gemfiles/rails_6.0.gemfile
23
+ - gemfiles/rails_edge.gemfile
14
24
  matrix:
25
+ exclude:
26
+ - rvm: 2.2
27
+ gemfile: gemfiles/rails_6.0.gemfile
28
+ - rvm: 2.3
29
+ gemfile: gemfiles/rails_6.0.gemfile
30
+ - rvm: 2.4
31
+ gemfile: gemfiles/rails_6.0.gemfile
32
+ - rvm: 2.2
33
+ gemfile: gemfiles/rails_edge.gemfile
34
+ - rvm: 2.3
35
+ gemfile: gemfiles/rails_edge.gemfile
36
+ - rvm: 2.4
37
+ gemfile: gemfiles/rails_edge.gemfile
15
38
  allow_failures:
16
39
  - rvm: rbx-2
17
- - rvm: jruby
40
+ - rvm: ruby-head
41
+ - rvm: jruby-head
42
+ - gemfile: gemfiles/rails_edge.gemfile
43
+
@@ -0,0 +1,16 @@
1
+ appraise 'rails_5.0' do
2
+ gem 'activerecord', '~> 5.0'
3
+ gem 'activemodel', '~> 5.0'
4
+ end
5
+
6
+ appraise 'rails_5.1' do
7
+ gem 'activerecord', '~> 5.1'
8
+ gem 'activemodel', '~> 5.1'
9
+ end
10
+
11
+ appraise 'rails_edge' do
12
+ gem 'rails', github: 'rails/rails', branch: 'master'
13
+ gem 'activerecord', github: 'rails/rails', branch: 'master'
14
+ gem 'activemodel', github: 'rails/rails', branch: 'master'
15
+ gem 'arel', github: 'rails/arel', branch: 'master'
16
+ end
data/README.md CHANGED
@@ -1,5 +1,5 @@
1
1
  [![Build Status](https://travis-ci.org/state-machines/state_machines-audit_trail.svg?branch=master)](https://travis-ci.org/state-machines/state_machines-audit_trail)
2
- [![Code Climate](https://codeclimate.com/github/state-machines/state_machines-audit_trail.png)](https://codeclimate.com/github/state-machines/state_machines-audit_trail)
2
+ [![Code Climate](https://codeclimate.com/github/state-machines/state_machines-audit_trail.svg)](https://codeclimate.com/github/state-machines/state_machines-audit_trail)
3
3
 
4
4
  # state_machines-audit_trail
5
5
  Log transitions on a [state_machines gem](https://github.com/state-machines/state_machines) to support auditing and business process analytics.
@@ -12,7 +12,7 @@ for any state machine. Having an audit trail gives you a complete history of the
12
12
  to investigate incidents or perform analytics, like: _"How long does it take on average to go from state a to state b?"_,
13
13
  or _"What percentage of cases goes from state a to b via state c?"_
14
14
 
15
- For more information read [Why developers should be force-fed state machines](http://www.shopify.com/technology/3383012-why-developers-should-be-force-fed-state-machines).
15
+ For more information read [Why developers should be force-fed state machines](https://engineering.shopify.com/blogs/engineering/17488160-why-developers-should-be-force-fed-state-machines).
16
16
 
17
17
  ## ORM support
18
18
 
@@ -56,7 +56,7 @@ will generate the `SubscriptionStateTransition` model and an accompanying migrat
56
56
 
57
57
  ```ruby
58
58
  class Subscription < ActiveRecord::Base
59
- state_machines :state, initial: :start do
59
+ state_machine :state, initial: :start do
60
60
  audit_trail
61
61
  ...
62
62
  ```
@@ -64,6 +64,10 @@ class Subscription < ActiveRecord::Base
64
64
  ### That's it!
65
65
  `audit_trail` will register an `after_transition` callback that is used to log all transitions including the initial state if there is one.
66
66
 
67
+ ## Upgrading from state_machine-audit_trail
68
+
69
+ See the wiki, https://github.com/state-machines/state_machines-audit_trail/wiki/Converting-from-former-state_machine-audit_trail-to-state_machines-audit_trail
70
+
67
71
  ## Configuration options
68
72
 
69
73
  ### `:initial` - turn off initial state logging
@@ -97,7 +101,7 @@ In order to utilize this feature, you need to:
97
101
  #### Example 1 - Store a single attribute value
98
102
  Store `Subscription` `field1` in `Transition` field `field1`:
99
103
  ```ruby
100
- audit_trail :context: :field1
104
+ audit_trail context: :field1
101
105
  ```
102
106
 
103
107
  #### Example 2 - Store multiple attribute values
@@ -106,7 +110,25 @@ Store `Subscription` `field1` and `field2` in `Transition` fields `field1` and `
106
110
  audit_trail context: [:field1, :field2]
107
111
  ```
108
112
 
109
- #### Example 3 - Store simple method results
113
+ #### Example 3 - Store multiple values from a single context object
114
+ Store `Subscription` `user` in `Transition` fields `user_id` and `user_name`:
115
+ ```ruby
116
+ class Subscription < ActiveRecord::Base
117
+ state_machine :state, initial: :start do
118
+ audit_trail context: :user
119
+ ...
120
+ end
121
+ end
122
+
123
+ class SubscriptionStateTransition < ActiveRecord::Base
124
+ def user=(u)
125
+ self.user_id = u.id
126
+ self.user_name = u.name
127
+ end
128
+ end
129
+ ```
130
+
131
+ #### Example 4 - Store simple method results
110
132
  Store simple method results.
111
133
 
112
134
  Sometimes it can be useful to store dynamically computed information, such as those from a `Subscription` method `#plan_time_remaining`
@@ -114,7 +136,7 @@ Sometimes it can be useful to store dynamically computed information, such as th
114
136
 
115
137
  ```ruby
116
138
  class Subscription < ActiveRecord::Base
117
- state_machines :state, initial: :start do
139
+ state_machine :state, initial: :start do
118
140
  audit_trail :context: :plan_time_remaining
119
141
  ...
120
142
 
@@ -123,12 +145,12 @@ class Subscription < ActiveRecord::Base
123
145
  ...
124
146
  ```
125
147
 
126
- #### Example 4 - Store advanced method results
148
+ #### Example 5 - Store advanced method results
127
149
  Store method results that interrogate the transition for information such as `event` arguments:
128
150
 
129
151
  ```ruby
130
152
  class Subscription < ActiveRecord::Base
131
- state_machines :state, initial: :start do
153
+ state_machine :state, initial: :start do
132
154
  audit_trail :context: :user_name
133
155
  ...
134
156
 
data/Rakefile CHANGED
@@ -6,4 +6,10 @@ RSpec::Core::RakeTask.new(:spec) do |task|
6
6
  task.rspec_opts = ['--color']
7
7
  end
8
8
 
9
- task :default => [:spec]
9
+ if ENV['APPRAISAL_INITIALIZED'] || ENV['TRAVIS']
10
+ task :default => :spec
11
+ else
12
+ require 'appraisal'
13
+ Appraisal::Task.new
14
+ task :default => :appraisal
15
+ end
@@ -0,0 +1,9 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 5.0.0"
6
+ gem "activemodel", "~> 5.0.0"
7
+ gem "sqlite3", "~> 1.3.6"
8
+
9
+ gemspec path: "../"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 5.1.0"
6
+ gem "activemodel", "~> 5.1.0"
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 5.2.0"
6
+ gem "activemodel", "~> 5.2.0"
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,8 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "activerecord", "~> 6.0.0"
6
+ gem "activemodel", "~> 6.0.0"
7
+
8
+ gemspec path: "../"
@@ -0,0 +1,10 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rails", github: "rails/rails", branch: "master"
6
+ gem "activerecord", github: "rails/rails", branch: "master"
7
+ gem "activemodel", github: "rails/rails", branch: "master"
8
+ gem "arel", github: "rails/arel", branch: "master"
9
+
10
+ gemspec path: "../"
@@ -1,2 +1,3 @@
1
+ # Comment here to test travis build on gem PR with no meaningful changes
1
2
  # To keep Rails happy
2
3
  require 'state_machines/audit_trail'
@@ -1,4 +1,4 @@
1
- class StateMachines::AuditTrail::Backend < Struct.new(:transition_class, :owner_class, :context)
1
+ class StateMachines::AuditTrail::Backend < Struct.new(:transition_class, :owner_class, :options)
2
2
 
3
3
  autoload :Mongoid, 'state_machines/audit_trail/backend/mongoid'
4
4
  autoload :ActiveRecord, 'state_machines/audit_trail/backend/active_record'
@@ -9,10 +9,18 @@ class StateMachines::AuditTrail::Backend < Struct.new(:transition_class, :owner_
9
9
  # - transition: state machine transition object that state machine passes to after/before transition callbacks
10
10
  #
11
11
  def log(object, transition)
12
- fields = {event: transition.event ? transition.event.to_s : nil, from: transition.from, to: transition.to}
13
- [context].flatten(1).each { |field|
12
+
13
+ if transition.machine.presence
14
+ # full transition object
15
+ namespace = transition.machine.namespace
16
+ else
17
+ # initial state open struct
18
+ namespace = transition.namespace
19
+ end
20
+ fields = {namespace: namespace, event: transition.event ? transition.event.to_s : nil, from: transition.from, to: transition.to}
21
+ [*options[:context]].each { |field|
14
22
  fields[field] = resolve_context(object, field, transition)
15
- } unless self.context.nil?
23
+ }
16
24
 
17
25
  # begin
18
26
  persist(object, fields)
@@ -30,16 +38,21 @@ class StateMachines::AuditTrail::Backend < Struct.new(:transition_class, :owner_
30
38
  # To add a new ORM, implement something similar to lib/state_machines/audit_trail/backend/active_record.rb
31
39
  # and return from here the appropriate object based on which ORM the transition_class is using
32
40
  #
33
- def self.create_for(transition_class, owner_class, context = nil)
41
+ def self.create_for(transition_class, owner_class, options = {})
34
42
  if Object.const_defined?('ActiveRecord') && transition_class.ancestors.include?(::ActiveRecord::Base)
35
- return StateMachines::AuditTrail::Backend::ActiveRecord.new(transition_class, owner_class, context)
43
+ return StateMachines::AuditTrail::Backend::ActiveRecord.new(transition_class, owner_class, options)
36
44
  elsif Object.const_defined?('Mongoid') && transition_class.ancestors.include?(::Mongoid::Document)
37
- return StateMachines::AuditTrail::Backend::Mongoid.new(transition_class, owner_class, context)
45
+ return StateMachines::AuditTrail::Backend::Mongoid.new(transition_class, owner_class, options)
38
46
  else
39
47
  raise 'Not implemented. Only support for ActiveRecord and Mongoid is implemented. Pull requests welcome.'
40
48
  end
41
49
  end
42
50
 
51
+ # Exists in case ORM layer has a different way of answering this question, but works for most.
52
+ def new_record?(object)
53
+ object.new_record?
54
+ end
55
+
43
56
  protected
44
57
 
45
58
  def persist(object, fields)
@@ -47,7 +60,15 @@ class StateMachines::AuditTrail::Backend < Struct.new(:transition_class, :owner_
47
60
  end
48
61
 
49
62
  def resolve_context(object, context, transition)
50
- if object.method(context).arity != 0
63
+ # ---------------
64
+ # TODO: remove this check after we set a minimum version of Rails/ActiveRecord to 5.1+. At that time, the argument will be removed and the arity check will be enough. - rosskevin
65
+ # Don't send params to Rails 5+ associations because it triggers a ton of deprecation messages.
66
+ # @see https://github.com/state-machines/state_machines-audit_trail/issues/6
67
+ # check if activerecord && the context is an association
68
+ skip_args = object.is_a?(::ActiveRecord::Base) && object.class.reflections.keys.include?(context.to_s)
69
+ # ---------------
70
+
71
+ if object.method(context).arity != 0 && !skip_args
51
72
  object.send(context, transition)
52
73
  else
53
74
  object.send(context)
@@ -1,13 +1,11 @@
1
1
  require 'state_machines-activerecord'
2
2
 
3
3
  class StateMachines::AuditTrail::Backend::ActiveRecord < StateMachines::AuditTrail::Backend
4
- attr_accessor :context
5
-
6
- def initialize(transition_class, owner_class, context = nil)
4
+ def initialize(transition_class, owner_class, options = {})
5
+ super
7
6
  @association = transition_class.to_s.tableize.split('/').last.to_sym
8
- super transition_class, owner_class
9
- self.context = context # FIXME: actually not sure why we need to do this, but tests fail otherwise. Something with super's Struct?
10
- owner_class.has_many(@association, class_name: transition_class.to_s) unless owner_class.reflect_on_association(@association)
7
+ assoc_options = {class_name: transition_class.to_s}.merge(options.slice(:as))
8
+ owner_class.has_many(@association, **assoc_options) unless owner_class.reflect_on_association(@association)
11
9
  end
12
10
 
13
11
  def persist(object, fields)
@@ -12,6 +12,7 @@ module StateMachines::AuditTrail::TransitionAuditing
12
12
  #
13
13
  # options:
14
14
  # - :class - custom state transition class
15
+ # - :owner_class - the class which is to own the persisted transition objects
15
16
  # - :context - methods to call/store in field of same name in the state transition class
16
17
  # - :initial - if false, won't log null => initial state transition upon instantiation
17
18
  #
@@ -21,18 +22,21 @@ module StateMachines::AuditTrail::TransitionAuditing
21
22
  raise ":class option[#{options[:class]}] must be a class (not a string)." unless options[:class].is_a? Class
22
23
  end
23
24
  transition_class = options[:class] || default_transition_class
25
+ owner_class = options[:owner_class] || self.owner_class
24
26
 
25
27
  # backend implements #log to store transition information
26
- @backend = StateMachines::AuditTrail::Backend.create_for(transition_class, self.owner_class, options[:context])
28
+ @backend = StateMachines::AuditTrail::Backend.create_for(transition_class, owner_class, options.slice(:context, :as))
27
29
 
28
30
  # Initial state logging can be turned off. Very useful for a model with multiple state_machines using a single TransitionState object for logging
29
31
  unless options[:initial] == false
30
32
  unless state_machine.action == nil
31
33
  # Log the initial transition from null => initial (upon object instantiation)
32
34
  state_machine.owner_class.after_initialize do |object|
33
- current_state = object.send(state_machine.attribute)
34
- if !current_state.nil?
35
- state_machine.backend.log(object, OpenStruct.new(to: current_state))
35
+ if state_machine.backend.new_record? object
36
+ current_state = object.send(state_machine.attribute)
37
+ if !current_state.nil?
38
+ state_machine.backend.log(object, OpenStruct.new(namespace: state_machine.namespace, to: current_state))
39
+ end
36
40
  end
37
41
  end
38
42
  end
@@ -1,5 +1,5 @@
1
1
  module StateMachines
2
2
  module AuditTrail
3
- VERSION = '1.0.0'
3
+ VERSION = '2.0.2'
4
4
  end
5
5
  end
@@ -12,6 +12,7 @@ class StateMachines::AuditTrailGenerator < ::Rails::Generators::Base
12
12
  def create_model
13
13
  args = [transition_class_name,
14
14
  "#{source_model.demodulize.tableize.singularize}:references",
15
+ 'namespace:string',
15
16
  'event:string',
16
17
  'from:string',
17
18
  'to:string',
@@ -6,6 +6,11 @@ ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':me
6
6
  class ARModelStateTransition < ActiveRecord::Base
7
7
  belongs_to :ar_model
8
8
  end
9
+
10
+ class ARModelWithNamespaceFooStateTransition < ActiveRecord::Base
11
+ belongs_to :ar_model_with_namespace
12
+ end
13
+
9
14
  class ARModelNoInitialStateTransition < ActiveRecord::Base
10
15
  belongs_to :ar_model_no_initial
11
16
  end
@@ -32,7 +37,7 @@ end
32
37
 
33
38
  class ARModel < ActiveRecord::Base
34
39
 
35
- state_machine :state, initial: :waiting do # log initial state?
40
+ state_machine :state, initial: :waiting do
36
41
  audit_trail
37
42
 
38
43
  event :start do
@@ -47,7 +52,7 @@ end
47
52
 
48
53
  class ARModelNoInitial < ActiveRecord::Base
49
54
 
50
- state_machine :state, initial: :waiting do # log initial state?
55
+ state_machine :state, initial: :waiting do
51
56
  audit_trail initial: false
52
57
 
53
58
  event :start do
@@ -59,9 +64,25 @@ class ARModelNoInitial < ActiveRecord::Base
59
64
  end
60
65
  end
61
66
  end
67
+
68
+ class ARModelWithNamespace < ActiveRecord::Base
69
+
70
+ state_machine :foo_state, initial: :waiting, namespace: :foo do
71
+ audit_trail
72
+
73
+ event :start do
74
+ transition [:waiting, :stopped] => :started
75
+ end
76
+
77
+ event :stop do
78
+ transition :started => :stopped
79
+ end
80
+ end
81
+ end
82
+
62
83
  #
63
84
  class ARModelWithContext < ActiveRecord::Base
64
- state_machine :state, initial: :waiting do # log initial state?
85
+ state_machine :state, initial: :waiting do
65
86
  audit_trail context: :context
66
87
 
67
88
  event :start do
@@ -79,7 +100,7 @@ class ARModelWithContext < ActiveRecord::Base
79
100
  end
80
101
 
81
102
  class ARModelWithMultipleContext < ActiveRecord::Base
82
- state_machine :state, initial: :waiting do # log initial state?
103
+ state_machine :state, initial: :waiting do
83
104
  audit_trail context: [:context, :second_context, :context_with_args]
84
105
 
85
106
  event :start do
@@ -150,14 +171,46 @@ class ARModelWithMultipleStateMachines < ActiveRecord::Base
150
171
  end
151
172
  end
152
173
 
153
- module SomeNamespace
174
+ class ARResourceStateTransition < ActiveRecord::Base
175
+ belongs_to :resource, polymorphic: true
176
+ end
177
+
178
+ class ARFirstModelWithPolymorphicStateTransition < ActiveRecord::Base
179
+ state_machine :state, :initial => :pending do
180
+ audit_trail class: ARResourceStateTransition, as: :ar_resource
181
+
182
+ event :start do
183
+ transition :pending => :in_progress
184
+ end
185
+
186
+ event :finish do
187
+ transition :in_progress => :complete
188
+ end
189
+ end
190
+ end
191
+
192
+ class ARSecondModelWithPolymorphicStateTransition < ActiveRecord::Base
193
+ state_machine :state, :initial => :pending do
194
+ audit_trail class: ARResourceStateTransition, as: :ar_resource
195
+
196
+ event :start do
197
+ transition :pending => :in_progress
198
+ end
199
+
200
+ event :finish do
201
+ transition :in_progress => :complete
202
+ end
203
+ end
204
+ end
205
+
206
+ module SomeModule
154
207
  class ARModelStateTransition < ActiveRecord::Base
155
- belongs_to :test_model
208
+ belongs_to :ar_model
156
209
  end
157
210
 
158
211
  class ARModel < ActiveRecord::Base
159
212
 
160
- state_machine :state, initial: :waiting do # log initial state?
213
+ state_machine :state, initial: :waiting do
161
214
  audit_trail
162
215
 
163
216
  event :start do
@@ -174,9 +227,13 @@ end
174
227
  #
175
228
  # Generate tables
176
229
  #
177
- def create_model_table(owner_class, multiple_state_machines = false)
230
+ def create_model_table(owner_class, multiple_state_machines = false, state_column = nil)
178
231
  ActiveRecord::Base.connection.create_table(owner_class.name.tableize) do |t|
179
- t.string :state unless multiple_state_machines
232
+ if state_column.presence
233
+ t.string state_column
234
+ else
235
+ t.string :state unless multiple_state_machines
236
+ end
180
237
  t.string :type
181
238
 
182
239
  if multiple_state_machines
@@ -189,19 +246,21 @@ def create_model_table(owner_class, multiple_state_machines = false)
189
246
  end
190
247
  end
191
248
 
192
- create_model_table(ARModel)
193
- create_model_table(ARModelNoInitial)
194
- create_model_table(ARModelWithContext)
195
- create_model_table(ARModelWithMultipleContext)
196
- create_model_table(ARModelWithMultipleStateMachines, true)
197
249
 
250
+ %w(ARModel ARModelNoInitial ARModelWithContext ARModelWithMultipleContext ARFirstModelWithPolymorphicStateTransition ARSecondModelWithPolymorphicStateTransition).each do |name|
251
+ create_model_table(name.constantize)
252
+ end
253
+
254
+ create_model_table(ARModelWithNamespace, false, :foo_state)
255
+ create_model_table(ARModelWithMultipleStateMachines, true)
198
256
 
199
- def create_transition_table(owner_class, state, add_context = false)
200
- class_name = "#{owner_class.name}#{state.to_s.camelize}Transition"
257
+ def create_transition_table(owner_class_name, state, add_context: false, polymorphic: false)
258
+ class_name = "#{owner_class_name}#{state.to_s.camelize}Transition"
201
259
  ActiveRecord::Base.connection.create_table(class_name.tableize) do |t|
202
260
 
203
- # t.references :"#{owner_class.name.pluralize.demodulize.tableize}"
204
- t.integer owner_class.name.foreign_key
261
+ t.references "#{owner_class_name.demodulize.underscore}", index: false, polymorphic: polymorphic
262
+ # t.integer owner_class_name.foreign_key
263
+ t.string :namespace
205
264
  t.string :event
206
265
  t.string :from
207
266
  t.string :to
@@ -213,10 +272,14 @@ def create_transition_table(owner_class, state, add_context = false)
213
272
  end
214
273
  end
215
274
 
216
- create_transition_table(ARModel, :state)
217
- create_transition_table(ARModelNoInitial, :state)
218
- create_transition_table(ARModelWithContext, :state, true)
219
- create_transition_table(ARModelWithMultipleContext, :state, true)
220
- create_transition_table(ARModelWithMultipleStateMachines, :first)
221
- create_transition_table(ARModelWithMultipleStateMachines, :second)
222
- create_transition_table(ARModelWithMultipleStateMachines, :third)
275
+ %w(ARModel ARModelNoInitial).each do |name|
276
+ create_transition_table(name, :state)
277
+ end
278
+
279
+ create_transition_table("ARModelWithNamespace", :foo_state, add_context: false)
280
+ create_transition_table("ARModelWithContext", :state, add_context: true)
281
+ create_transition_table("ARModelWithMultipleContext", :state, add_context: true)
282
+ create_transition_table("ARModelWithMultipleStateMachines", :first)
283
+ create_transition_table("ARModelWithMultipleStateMachines", :second)
284
+ create_transition_table("ARModelWithMultipleStateMachines", :third)
285
+ create_transition_table("ARResource", :state, polymorphic: true)
@@ -9,6 +9,7 @@ class MongoidTestModelStateTransition
9
9
  include Mongoid::Timestamps
10
10
  belongs_to :mongoid_test_model
11
11
 
12
+ field :namespace, type: String
12
13
  field :event, type: String
13
14
  field :from, type: String
14
15
  field :to, type: String
@@ -19,6 +20,7 @@ class MongoidTestModelWithMultipleStateMachinesFirstTransition
19
20
  include Mongoid::Timestamps
20
21
  belongs_to :mongoid_test_model
21
22
 
23
+ field :namespace, type: String
22
24
  field :event, type: String
23
25
  field :from, type: String
24
26
  field :to, type: String
@@ -29,6 +31,7 @@ class MongoidTestModelWithMultipleStateMachinesSecondTransition
29
31
  include Mongoid::Timestamps
30
32
  belongs_to :mongoid_test_model
31
33
 
34
+ field :namespace, type: String
32
35
  field :event, type: String
33
36
  field :from, type: String
34
37
  field :to, type: String
@@ -1,5 +1,5 @@
1
1
  test:
2
- sessions:
2
+ clients:
3
3
  default:
4
4
  database: sm_audit_trail
5
5
  hosts:
@@ -9,20 +9,35 @@ require 'helpers/active_record'
9
9
  describe StateMachines::AuditTrail::Backend::ActiveRecord do
10
10
 
11
11
  context ':initial option' do
12
- it 'default logs' do
13
- target = ARModel.new
14
- # initial transition is built but not saved
15
- expect(target.new_record?).to be_truthy
16
- expect(target.ar_model_state_transitions.count).to eq 0
17
- target.save!
12
+ context 'default' do
13
+ it 'new object' do
14
+ target = ARModel.new
15
+ # initial transition is built but not saved
16
+ expect(target.new_record?).to be_truthy
17
+ expect(target.ar_model_state_transitions.count).to eq 0
18
+ target.save!
19
+
20
+ # initial transition is saved and should be present
21
+ expect(target.new_record?).to be_falsey
22
+ expect(target.ar_model_state_transitions.count).to eq 1
23
+ state_transition = target.ar_model_state_transitions.first
24
+ assert_transition state_transition, nil, nil, 'waiting'
25
+ end
18
26
 
19
- # initial transition is saved and should be present
20
- expect(target.new_record?).to be_falsey
21
- expect(target.ar_model_state_transitions.count).to eq 1
22
- state_transition = target.ar_model_state_transitions.first
23
- expect(state_transition.from).to be_nil
24
- expect(state_transition.to).to eq 'waiting'
25
- expect(state_transition.event).to be_nil
27
+ it 'create object' do
28
+ target = ARModel.create!
29
+ # initial transition is saved and should be present
30
+ expect(target.new_record?).to be_falsey
31
+ expect(target.ar_model_state_transitions.count).to eq 1
32
+ state_transition = target.ar_model_state_transitions.first
33
+ assert_transition state_transition, nil, nil, 'waiting'
34
+
35
+ # ensure we don't have a second initial state transition logged (issue #4)
36
+ target = target.reload()
37
+ expect(target.ar_model_state_transitions.count).to eq 1
38
+ state_transition = target.ar_model_state_transitions.first
39
+ assert_transition state_transition, nil, nil, 'waiting'
40
+ end
26
41
  end
27
42
 
28
43
  it 'false skips log' do
@@ -38,6 +53,32 @@ describe StateMachines::AuditTrail::Backend::ActiveRecord do
38
53
  end
39
54
  end
40
55
 
56
+ context 'namespaced state_machine' do
57
+ it 'should log namespace' do
58
+ target = ARModelWithNamespace.create!
59
+
60
+ # initial transition is saved and should be present
61
+ expect(target.new_record?).to be_falsey
62
+ expect(target.ar_model_with_namespace_foo_state_transitions.count).to eq 1
63
+ state_transition = target.ar_model_with_namespace_foo_state_transitions.first
64
+ expect(state_transition.namespace).to eq 'foo'
65
+ expect(state_transition.from).to be_nil
66
+ expect(state_transition.to).to eq 'waiting'
67
+ expect(state_transition.event).to be_nil
68
+ end
69
+
70
+ it 'should not log namespace' do
71
+ target = ARModel.create!
72
+ expect(target.new_record?).to be_falsey
73
+ expect(target.ar_model_state_transitions.count).to eq 1
74
+ state_transition = target.ar_model_state_transitions.first
75
+ expect(state_transition.namespace).to be_nil
76
+ expect(state_transition.from).to be_nil
77
+ expect(state_transition.to).to eq 'waiting'
78
+ expect(state_transition.event).to be_nil
79
+ end
80
+ end
81
+
41
82
  context '#create_for' do
42
83
  it 'should be Backend::ActiveRecord' do
43
84
  backend = StateMachines::AuditTrail::Backend.create_for(ARModelWithContextStateTransition, ARModel)
@@ -49,13 +90,13 @@ describe StateMachines::AuditTrail::Backend::ActiveRecord do
49
90
  expect(ARModel.reflect_on_association(:ar_model_state_transitions).collection?).to be_truthy
50
91
  end
51
92
 
52
- it 'should handle namespaced models' do
53
- StateMachines::AuditTrail::Backend.create_for(ARModelWithContextStateTransition, SomeNamespace::ARModel)
54
- expect(SomeNamespace::ARModel.reflect_on_association(:ar_model_state_transitions).collection?).to be_truthy
93
+ it 'should handle models within modules' do
94
+ StateMachines::AuditTrail::Backend.create_for(ARModelWithContextStateTransition, SomeModule::ARModel)
95
+ expect(SomeModule::ARModel.reflect_on_association(:ar_model_state_transitions).collection?).to be_truthy
55
96
  end
56
97
 
57
- it 'should handle namespaced state transition model' do
58
- StateMachines::AuditTrail::Backend.create_for(SomeNamespace::ARModelStateTransition, ARModel)
98
+ it 'should handle state transition models within modules' do
99
+ StateMachines::AuditTrail::Backend.create_for(SomeModule::ARModelStateTransition, ARModel)
59
100
  expect(ARModel.reflect_on_association(:ar_model_state_transitions).collection?).to be_truthy
60
101
  end
61
102
  end
@@ -106,7 +147,7 @@ describe StateMachines::AuditTrail::Backend::ActiveRecord do
106
147
 
107
148
  context 'wants to log a single context' do
108
149
  before(:each) do
109
- StateMachines::AuditTrail::Backend.create_for(ARModelWithContextStateTransition, ARModelWithContext, :context)
150
+ StateMachines::AuditTrail::Backend.create_for(ARModelWithContextStateTransition, ARModelWithContext, context: :context)
110
151
  end
111
152
 
112
153
  let!(:target) { ARModelWithContext.create! }
@@ -120,7 +161,7 @@ describe StateMachines::AuditTrail::Backend::ActiveRecord do
120
161
 
121
162
  context 'wants to log multiple context fields' do
122
163
  before(:each) do
123
- StateMachines::AuditTrail::Backend.create_for(ARModelWithMultipleContextStateTransition, ARModelWithMultipleContext, [:context, :second_context, :context_with_args])
164
+ StateMachines::AuditTrail::Backend.create_for(ARModelWithMultipleContextStateTransition, ARModelWithMultipleContext, context: [:context, :second_context, :context_with_args])
124
165
  end
125
166
 
126
167
  let!(:target) { ARModelWithMultipleContext.create! }
@@ -222,4 +263,26 @@ describe StateMachines::AuditTrail::Backend::ActiveRecord do
222
263
  expect { m.complete! }.not_to raise_error
223
264
  end
224
265
  end
266
+
267
+ context 'polymorphic' do
268
+ it 'creates polymorphic state transitions' do
269
+ m1 = ARFirstModelWithPolymorphicStateTransition.create!
270
+ m2 = ARSecondModelWithPolymorphicStateTransition.create!
271
+ m2.start!
272
+ m2.finish!
273
+
274
+ expect(m1.ar_resource_state_transitions.count).to eq(1)
275
+ expect(m2.ar_resource_state_transitions.count).to eq(3)
276
+ expect(ARResourceStateTransition.count).to eq(4)
277
+ end
278
+ end
279
+
280
+ private
281
+
282
+ def assert_transition(state_transition, event, from, to)
283
+ # expect(state_transition.namespace).to eq namespace
284
+ expect(state_transition.event).to eq event
285
+ expect(state_transition.from).to eq from
286
+ expect(state_transition.to).to eq to
287
+ end
225
288
  end
@@ -1,98 +1,98 @@
1
- # reset integrations so that something like ActiveRecord is not loaded and conflicting
2
- require 'state_machines'
3
- StateMachines::Integrations.reset
4
-
5
- require 'spec_helper'
6
- require 'state_machines-mongoid'
7
- require 'helpers/mongoid'
8
-
9
- describe StateMachines::AuditTrail::Backend::Mongoid do
10
-
11
- context '#create_for' do
12
- it 'should create a Mongoid backend' do
13
- backend = StateMachines::AuditTrail::Backend.create_for(MongoidTestModelStateTransition, MongoidTestModel)
14
- expect(backend).to be_instance_of(StateMachines::AuditTrail::Backend::Mongoid)
15
- end
16
- end
17
-
18
- context 'single state machine' do
19
- let!(:target) { MongoidTestModel.create! }
20
-
21
- it 'should populate all fields' do
22
- target.start!
23
- last_transition = MongoidTestModelStateTransition.where(:mongoid_test_model_id => target.id).last
24
-
25
- expect(last_transition.event).to eq 'start'
26
- expect(last_transition.from).to eq 'waiting'
27
- expect(last_transition.to).to eq 'started'
28
- expect(last_transition.created_at).to be_within(10.seconds).of(DateTime.now)
29
- end
30
-
31
- it 'should log multiple events' do
32
- expect { target.start && target.stop && target.start }.to change(MongoidTestModelStateTransition, :count).by(3)
33
- end
34
-
35
- it 'do nothing on failed transition' do
36
- expect { target.stop }.not_to change(MongoidTestModelStateTransition, :count)
37
- end
38
- end
39
-
40
- context 'multiple state machines' do
41
- let!(:target) { MongoidTestModelWithMultipleStateMachines.create! }
42
-
43
- it 'should log a state transition for the affected state machine' do
44
- expect { target.begin_first! }.to change(MongoidTestModelWithMultipleStateMachinesFirstTransition, :count).by(1)
45
- end
46
-
47
- it 'should not log a state transition for the unaffected state machine' do
48
- expect { target.begin_first! }.not_to change(MongoidTestModelWithMultipleStateMachinesSecondTransition, :count)
49
- end
50
- end
51
-
52
- context 'on an object with a state machine having an initial state' do
53
- let(:target_class) { MongoidTestModelWithMultipleStateMachines }
54
- let(:state_transition_class) { MongoidTestModelWithMultipleStateMachinesFirstTransition }
55
-
56
- it 'should log a state transition for the inital state' do
57
- expect { target_class.create! }.to change(state_transition_class, :count).by(1)
58
- end
59
-
60
- it 'should only set the :to state for the initial transition' do
61
- target_class.create!
62
- initial_transition = state_transition_class.last
63
- expect(initial_transition.event).to be_nil
64
- expect(initial_transition.from).to be_nil
65
- expect(initial_transition.to).to eq 'beginning'
66
- expect(initial_transition.created_at).to be_within(10.seconds).of(DateTime.now)
67
- end
68
- end
69
-
70
- context 'on an object with a state machine not having an initial state' do
71
- let(:target_class) { MongoidTestModelWithMultipleStateMachines }
72
- let(:state_transition_class) { MongoidTestModelWithMultipleStateMachinesSecondTransition }
73
-
74
- it 'should not log a transition when the object is created' do
75
- expect { target_class.create! }.not_to change(state_transition_class, :count)
76
- end
77
-
78
- it 'should log a transition for the first event' do
79
- expect { target_class.create.begin_second! }.to change(state_transition_class, :count).by(1)
80
- end
81
-
82
- it 'should not set a value for the :from state on the first transition' do
83
- target_class.create.begin_second!
84
- first_transition = state_transition_class.last
85
- expect(first_transition.event).to eq 'begin_second'
86
- expect(first_transition.from).to be_nil
87
- expect(first_transition.to).to eq 'beginning_second'
88
- expect(first_transition.created_at).to be_within(10.seconds).of(DateTime.now)
89
- end
90
- end
91
-
92
- context 'on a class using STI' do
93
- it 'should properly grab the class name from STI models' do
94
- m = MongoidTestModelDescendant.create!
95
- expect { m.start! }.not_to raise_error
96
- end
97
- end
98
- end
1
+ # # reset integrations so that something like ActiveRecord is not loaded and conflicting
2
+ # require 'state_machines'
3
+ # StateMachines::Integrations.reset
4
+ #
5
+ # require 'spec_helper'
6
+ # require 'state_machines-mongoid'
7
+ # require 'helpers/mongoid'
8
+ #
9
+ # describe StateMachines::AuditTrail::Backend::Mongoid do
10
+ #
11
+ # context '#create_for' do
12
+ # it 'should create a Mongoid backend' do
13
+ # backend = StateMachines::AuditTrail::Backend.create_for(MongoidTestModelStateTransition, MongoidTestModel)
14
+ # expect(backend).to be_instance_of(StateMachines::AuditTrail::Backend::Mongoid)
15
+ # end
16
+ # end
17
+ #
18
+ # context 'single state machine' do
19
+ # let!(:target) { MongoidTestModel.create! }
20
+ #
21
+ # it 'should populate all fields' do
22
+ # target.start!
23
+ # last_transition = MongoidTestModelStateTransition.where(:mongoid_test_model_id => target.id).last
24
+ #
25
+ # expect(last_transition.event).to eq 'start'
26
+ # expect(last_transition.from).to eq 'waiting'
27
+ # expect(last_transition.to).to eq 'started'
28
+ # expect(last_transition.created_at).to be_within(10.seconds).of(DateTime.now)
29
+ # end
30
+ #
31
+ # it 'should log multiple events' do
32
+ # expect { target.start && target.stop && target.start }.to change(MongoidTestModelStateTransition, :count).by(3)
33
+ # end
34
+ #
35
+ # it 'do nothing on failed transition' do
36
+ # expect { target.stop }.not_to change(MongoidTestModelStateTransition, :count)
37
+ # end
38
+ # end
39
+ #
40
+ # context 'multiple state machines' do
41
+ # let!(:target) { MongoidTestModelWithMultipleStateMachines.create! }
42
+ #
43
+ # it 'should log a state transition for the affected state machine' do
44
+ # expect { target.begin_first! }.to change(MongoidTestModelWithMultipleStateMachinesFirstTransition, :count).by(1)
45
+ # end
46
+ #
47
+ # it 'should not log a state transition for the unaffected state machine' do
48
+ # expect { target.begin_first! }.not_to change(MongoidTestModelWithMultipleStateMachinesSecondTransition, :count)
49
+ # end
50
+ # end
51
+ #
52
+ # context 'on an object with a state machine having an initial state' do
53
+ # let(:target_class) { MongoidTestModelWithMultipleStateMachines }
54
+ # let(:state_transition_class) { MongoidTestModelWithMultipleStateMachinesFirstTransition }
55
+ #
56
+ # it 'should log a state transition for the inital state' do
57
+ # expect { target_class.create! }.to change(state_transition_class, :count).by(1)
58
+ # end
59
+ #
60
+ # it 'should only set the :to state for the initial transition' do
61
+ # target_class.create!
62
+ # initial_transition = state_transition_class.last
63
+ # expect(initial_transition.event).to be_nil
64
+ # expect(initial_transition.from).to be_nil
65
+ # expect(initial_transition.to).to eq 'beginning'
66
+ # expect(initial_transition.created_at).to be_within(10.seconds).of(DateTime.now)
67
+ # end
68
+ # end
69
+ #
70
+ # context 'on an object with a state machine not having an initial state' do
71
+ # let(:target_class) { MongoidTestModelWithMultipleStateMachines }
72
+ # let(:state_transition_class) { MongoidTestModelWithMultipleStateMachinesSecondTransition }
73
+ #
74
+ # it 'should not log a transition when the object is created' do
75
+ # expect { target_class.create! }.not_to change(state_transition_class, :count)
76
+ # end
77
+ #
78
+ # it 'should log a transition for the first event' do
79
+ # expect { target_class.create.begin_second! }.to change(state_transition_class, :count).by(1)
80
+ # end
81
+ #
82
+ # it 'should not set a value for the :from state on the first transition' do
83
+ # target_class.create.begin_second!
84
+ # first_transition = state_transition_class.last
85
+ # expect(first_transition.event).to eq 'begin_second'
86
+ # expect(first_transition.from).to be_nil
87
+ # expect(first_transition.to).to eq 'beginning_second'
88
+ # expect(first_transition.created_at).to be_within(10.seconds).of(DateTime.now)
89
+ # end
90
+ # end
91
+ #
92
+ # context 'on a class using STI' do
93
+ # it 'should properly grab the class name from STI models' do
94
+ # m = MongoidTestModelDescendant.create!
95
+ # expect { m.start! }.not_to raise_error
96
+ # end
97
+ # end
98
+ # end
@@ -10,7 +10,7 @@
10
10
  # describe StateMachines::AuditTrailGenerator, type: :generator do
11
11
  #
12
12
  # destination File.expand_path('../../../../tmp', __FILE__)
13
- # arguments %w(SomeNamespace::Subscription state)
13
+ # arguments %w(SomeModule::Subscription state)
14
14
  #
15
15
  # before(:all) do
16
16
  # prepare_destination
@@ -36,7 +36,7 @@
36
36
  # end
37
37
  # directory 'some_namespace' do
38
38
  # file 'subscription_state_transition.rb' do
39
- # contains 'class SomeNamespace::SubscriptionStateTransition'
39
+ # contains 'class SomeModule::SubscriptionStateTransition'
40
40
  # end
41
41
  # end
42
42
  # end
@@ -22,12 +22,17 @@ Gem::Specification.new do |s|
22
22
  s.add_development_dependency('state_machines-mongoid')
23
23
  s.add_development_dependency('rake')
24
24
  s.add_development_dependency('rspec', '>= 3.0.0')
25
- s.add_development_dependency('activerecord', '>= 4.0.0')
26
- s.add_development_dependency('sqlite3')
27
- s.add_development_dependency('mongoid', '>= 4.0.0')
28
- s.add_development_dependency('bson_ext')
25
+ s.add_development_dependency('activerecord', '>= 5.0.0')
26
+ if(defined?(JRUBY_VERSION))
27
+ s.add_development_dependency('activerecord-jdbcsqlite3-adapter')
28
+ else
29
+ s.add_development_dependency('sqlite3')
30
+ end
31
+ s.add_development_dependency('mongoid', '>= 6.0.0.beta')
32
+ s.add_development_dependency('bson')
29
33
  s.add_development_dependency('generator_spec')
30
- s.add_development_dependency('rails', '>= 4.0.0')
34
+ s.add_development_dependency('rails', '>= 5.0.0')
35
+ s.add_development_dependency('appraisal', '~> 2.2.0')
31
36
 
32
37
  s.files = `git ls-files`.split($/).reject { |f| f =~ /^samples\// }
33
38
  s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: state_machines-audit_trail
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 2.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Ross
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2015-03-30 00:00:00.000000000 Z
13
+ date: 2020-06-09 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: state_machines
@@ -88,14 +88,14 @@ dependencies:
88
88
  requirements:
89
89
  - - ">="
90
90
  - !ruby/object:Gem::Version
91
- version: 4.0.0
91
+ version: 5.0.0
92
92
  type: :development
93
93
  prerelease: false
94
94
  version_requirements: !ruby/object:Gem::Requirement
95
95
  requirements:
96
96
  - - ">="
97
97
  - !ruby/object:Gem::Version
98
- version: 4.0.0
98
+ version: 5.0.0
99
99
  - !ruby/object:Gem::Dependency
100
100
  name: sqlite3
101
101
  requirement: !ruby/object:Gem::Requirement
@@ -116,16 +116,16 @@ dependencies:
116
116
  requirements:
117
117
  - - ">="
118
118
  - !ruby/object:Gem::Version
119
- version: 4.0.0
119
+ version: 6.0.0.beta
120
120
  type: :development
121
121
  prerelease: false
122
122
  version_requirements: !ruby/object:Gem::Requirement
123
123
  requirements:
124
124
  - - ">="
125
125
  - !ruby/object:Gem::Version
126
- version: 4.0.0
126
+ version: 6.0.0.beta
127
127
  - !ruby/object:Gem::Dependency
128
- name: bson_ext
128
+ name: bson
129
129
  requirement: !ruby/object:Gem::Requirement
130
130
  requirements:
131
131
  - - ">="
@@ -158,14 +158,28 @@ dependencies:
158
158
  requirements:
159
159
  - - ">="
160
160
  - !ruby/object:Gem::Version
161
- version: 4.0.0
161
+ version: 5.0.0
162
162
  type: :development
163
163
  prerelease: false
164
164
  version_requirements: !ruby/object:Gem::Requirement
165
165
  requirements:
166
166
  - - ">="
167
167
  - !ruby/object:Gem::Version
168
- version: 4.0.0
168
+ version: 5.0.0
169
+ - !ruby/object:Gem::Dependency
170
+ name: appraisal
171
+ requirement: !ruby/object:Gem::Requirement
172
+ requirements:
173
+ - - "~>"
174
+ - !ruby/object:Gem::Version
175
+ version: 2.2.0
176
+ type: :development
177
+ prerelease: false
178
+ version_requirements: !ruby/object:Gem::Requirement
179
+ requirements:
180
+ - - "~>"
181
+ - !ruby/object:Gem::Version
182
+ version: 2.2.0
169
183
  description: Log transitions on a state_machines to support auditing and business
170
184
  process analytics.
171
185
  email:
@@ -178,11 +192,19 @@ extra_rdoc_files: []
178
192
  files:
179
193
  - ".gitignore"
180
194
  - ".rspec"
195
+ - ".ruby-gemset"
196
+ - ".ruby-version"
181
197
  - ".travis.yml"
198
+ - Appraisals
182
199
  - Gemfile
183
200
  - LICENSE
184
201
  - README.md
185
202
  - Rakefile
203
+ - gemfiles/rails_5.0.gemfile
204
+ - gemfiles/rails_5.1.gemfile
205
+ - gemfiles/rails_5.2.gemfile
206
+ - gemfiles/rails_6.0.gemfile
207
+ - gemfiles/rails_edge.gemfile
186
208
  - lib/state_machines-audit_trail.rb
187
209
  - lib/state_machines/audit_trail.rb
188
210
  - lib/state_machines/audit_trail/backend.rb
@@ -220,8 +242,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
220
242
  - !ruby/object:Gem::Version
221
243
  version: '0'
222
244
  requirements: []
223
- rubyforge_project:
224
- rubygems_version: 2.4.5
245
+ rubygems_version: 3.0.3
225
246
  signing_key:
226
247
  specification_version: 4
227
248
  summary: Log transitions on a state_machines to support auditing and business process