state_machines-audit_trail 1.0.0 → 1.0.1
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/lib/state_machines/audit_trail/backend.rb +9 -1
- data/lib/state_machines/audit_trail/transition_auditing.rb +1 -1
- data/lib/state_machines/audit_trail/version.rb +1 -1
- data/lib/state_machines/audit_trail_generator.rb +1 -0
- data/spec/helpers/active_record.rb +46 -15
- data/spec/helpers/mongoid.rb +3 -0
- data/spec/lib/state_machines/audit_trail/backend/active_record_spec.rb +57 -18
- data/spec/lib/state_machines/audit_trail_generator_spec.rb +2 -2
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0f76b02dab1bbb82a2ba360cbc86137642fc3874
|
4
|
+
data.tar.gz: a40d8ce4c4f7166f9660669d8a603eb8da9d9e40
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9818ab2f5f3146c6444645cc6a92c331c069d842b00ff309bc8c4e8ff61fd09a396e0b5240ef43d6686fcdc8e42cc4dd23e6c8f1814ccd47efa3c2fb20aa3915
|
7
|
+
data.tar.gz: e85f0fee66e5323f67e1ffb4d8bb9cd42313d3e5e33ab846fc43a9b0b8bbcf79205c8cc6f2738d633ae450a4e11bf750de24a9a78d11cbc27ce0bc331f5640f3
|
@@ -9,7 +9,15 @@ 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
|
-
|
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}
|
13
21
|
[context].flatten(1).each { |field|
|
14
22
|
fields[field] = resolve_context(object, field, transition)
|
15
23
|
} unless self.context.nil?
|
@@ -32,7 +32,7 @@ module StateMachines::AuditTrail::TransitionAuditing
|
|
32
32
|
state_machine.owner_class.after_initialize do |object|
|
33
33
|
current_state = object.send(state_machine.attribute)
|
34
34
|
if !current_state.nil?
|
35
|
-
state_machine.backend.log(object, OpenStruct.new(to: current_state))
|
35
|
+
state_machine.backend.log(object, OpenStruct.new(namespace: state_machine.namespace, to: current_state))
|
36
36
|
end
|
37
37
|
end
|
38
38
|
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
|
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
|
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
|
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
|
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,14 @@ class ARModelWithMultipleStateMachines < ActiveRecord::Base
|
|
150
171
|
end
|
151
172
|
end
|
152
173
|
|
153
|
-
module
|
174
|
+
module SomeModule
|
154
175
|
class ARModelStateTransition < ActiveRecord::Base
|
155
|
-
belongs_to :
|
176
|
+
belongs_to :ar_model
|
156
177
|
end
|
157
178
|
|
158
179
|
class ARModel < ActiveRecord::Base
|
159
180
|
|
160
|
-
state_machine :state, initial: :waiting do
|
181
|
+
state_machine :state, initial: :waiting do
|
161
182
|
audit_trail
|
162
183
|
|
163
184
|
event :start do
|
@@ -174,9 +195,13 @@ end
|
|
174
195
|
#
|
175
196
|
# Generate tables
|
176
197
|
#
|
177
|
-
def create_model_table(owner_class, multiple_state_machines = false)
|
198
|
+
def create_model_table(owner_class, multiple_state_machines = false, state_column = nil)
|
178
199
|
ActiveRecord::Base.connection.create_table(owner_class.name.tableize) do |t|
|
179
|
-
|
200
|
+
if state_column.presence
|
201
|
+
t.string state_column
|
202
|
+
else
|
203
|
+
t.string :state unless multiple_state_machines
|
204
|
+
end
|
180
205
|
t.string :type
|
181
206
|
|
182
207
|
if multiple_state_machines
|
@@ -189,10 +214,12 @@ def create_model_table(owner_class, multiple_state_machines = false)
|
|
189
214
|
end
|
190
215
|
end
|
191
216
|
|
192
|
-
|
193
|
-
|
194
|
-
create_model_table(
|
195
|
-
|
217
|
+
|
218
|
+
%w(ARModel ARModelNoInitial ARModelWithContext ARModelWithMultipleContext).each do |name|
|
219
|
+
create_model_table(name.constantize)
|
220
|
+
end
|
221
|
+
|
222
|
+
create_model_table(ARModelWithNamespace, false, :foo_state)
|
196
223
|
create_model_table(ARModelWithMultipleStateMachines, true)
|
197
224
|
|
198
225
|
|
@@ -202,6 +229,7 @@ def create_transition_table(owner_class, state, add_context = false)
|
|
202
229
|
|
203
230
|
# t.references :"#{owner_class.name.pluralize.demodulize.tableize}"
|
204
231
|
t.integer owner_class.name.foreign_key
|
232
|
+
t.string :namespace
|
205
233
|
t.string :event
|
206
234
|
t.string :from
|
207
235
|
t.string :to
|
@@ -213,8 +241,11 @@ def create_transition_table(owner_class, state, add_context = false)
|
|
213
241
|
end
|
214
242
|
end
|
215
243
|
|
216
|
-
|
217
|
-
create_transition_table(
|
244
|
+
%w(ARModel ARModelNoInitial).each do |name|
|
245
|
+
create_transition_table(name.constantize, :state)
|
246
|
+
end
|
247
|
+
|
248
|
+
create_transition_table(ARModelWithNamespace, :foo_state, false)
|
218
249
|
create_transition_table(ARModelWithContext, :state, true)
|
219
250
|
create_transition_table(ARModelWithMultipleContext, :state, true)
|
220
251
|
create_transition_table(ARModelWithMultipleStateMachines, :first)
|
data/spec/helpers/mongoid.rb
CHANGED
@@ -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
|
@@ -9,20 +9,33 @@ require 'helpers/active_record'
|
|
9
9
|
describe StateMachines::AuditTrail::Backend::ActiveRecord do
|
10
10
|
|
11
11
|
context ':initial option' do
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
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
|
+
expect(state_transition.from).to be_nil
|
25
|
+
expect(state_transition.to).to eq 'waiting'
|
26
|
+
expect(state_transition.event).to be_nil
|
27
|
+
end
|
18
28
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
29
|
+
it 'create object' do
|
30
|
+
target = ARModel.create!
|
31
|
+
# initial transition is saved and should be present
|
32
|
+
expect(target.new_record?).to be_falsey
|
33
|
+
expect(target.ar_model_state_transitions.count).to eq 1
|
34
|
+
state_transition = target.ar_model_state_transitions.first
|
35
|
+
expect(state_transition.from).to be_nil
|
36
|
+
expect(state_transition.to).to eq 'waiting'
|
37
|
+
expect(state_transition.event).to be_nil
|
38
|
+
end
|
26
39
|
end
|
27
40
|
|
28
41
|
it 'false skips log' do
|
@@ -38,6 +51,32 @@ describe StateMachines::AuditTrail::Backend::ActiveRecord do
|
|
38
51
|
end
|
39
52
|
end
|
40
53
|
|
54
|
+
context 'namespaced state_machine' do
|
55
|
+
it 'should log namespace' do
|
56
|
+
target = ARModelWithNamespace.create!
|
57
|
+
|
58
|
+
# initial transition is saved and should be present
|
59
|
+
expect(target.new_record?).to be_falsey
|
60
|
+
expect(target.ar_model_with_namespace_foo_state_transitions.count).to eq 1
|
61
|
+
state_transition = target.ar_model_with_namespace_foo_state_transitions.first
|
62
|
+
expect(state_transition.namespace).to eq 'foo'
|
63
|
+
expect(state_transition.from).to be_nil
|
64
|
+
expect(state_transition.to).to eq 'waiting'
|
65
|
+
expect(state_transition.event).to be_nil
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should not log namespace' do
|
69
|
+
target = ARModel.create!
|
70
|
+
expect(target.new_record?).to be_falsey
|
71
|
+
expect(target.ar_model_state_transitions.count).to eq 1
|
72
|
+
state_transition = target.ar_model_state_transitions.first
|
73
|
+
expect(state_transition.namespace).to be_nil
|
74
|
+
expect(state_transition.from).to be_nil
|
75
|
+
expect(state_transition.to).to eq 'waiting'
|
76
|
+
expect(state_transition.event).to be_nil
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
41
80
|
context '#create_for' do
|
42
81
|
it 'should be Backend::ActiveRecord' do
|
43
82
|
backend = StateMachines::AuditTrail::Backend.create_for(ARModelWithContextStateTransition, ARModel)
|
@@ -49,13 +88,13 @@ describe StateMachines::AuditTrail::Backend::ActiveRecord do
|
|
49
88
|
expect(ARModel.reflect_on_association(:ar_model_state_transitions).collection?).to be_truthy
|
50
89
|
end
|
51
90
|
|
52
|
-
it 'should handle
|
53
|
-
StateMachines::AuditTrail::Backend.create_for(ARModelWithContextStateTransition,
|
54
|
-
expect(
|
91
|
+
it 'should handle models within modules' do
|
92
|
+
StateMachines::AuditTrail::Backend.create_for(ARModelWithContextStateTransition, SomeModule::ARModel)
|
93
|
+
expect(SomeModule::ARModel.reflect_on_association(:ar_model_state_transitions).collection?).to be_truthy
|
55
94
|
end
|
56
95
|
|
57
|
-
it 'should handle
|
58
|
-
StateMachines::AuditTrail::Backend.create_for(
|
96
|
+
it 'should handle state transition models within modules' do
|
97
|
+
StateMachines::AuditTrail::Backend.create_for(SomeModule::ARModelStateTransition, ARModel)
|
59
98
|
expect(ARModel.reflect_on_association(:ar_model_state_transitions).collection?).to be_truthy
|
60
99
|
end
|
61
100
|
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(
|
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
|
39
|
+
# contains 'class SomeModule::SubscriptionStateTransition'
|
40
40
|
# end
|
41
41
|
# end
|
42
42
|
# end
|