rollbacker 1.0.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.
- data/.gitignore +8 -0
- data/Gemfile +3 -0
- data/LICENSE +20 -0
- data/README.md +16 -0
- data/Rakefile +33 -0
- data/init.rb +1 -0
- data/lib/generators/rollbacker/migration/migration_generator.rb +26 -0
- data/lib/generators/rollbacker/migration/templates/migration.rb +22 -0
- data/lib/generators/rollbacker.rb +9 -0
- data/lib/rollbacker/base.rb +49 -0
- data/lib/rollbacker/change_validator.rb +30 -0
- data/lib/rollbacker/config.rb +34 -0
- data/lib/rollbacker/database_rollback.rb +28 -0
- data/lib/rollbacker/recorder.rb +57 -0
- data/lib/rollbacker/rollbacker_change.rb +25 -0
- data/lib/rollbacker/spec_helpers.rb +20 -0
- data/lib/rollbacker/status.rb +62 -0
- data/lib/rollbacker/user.rb +15 -0
- data/lib/rollbacker/version.rb +3 -0
- data/lib/rollbacker.rb +21 -0
- data/rollbacker.gemspec +22 -0
- data/spec/base_spec.rb +127 -0
- data/spec/change_validator_spec.rb +74 -0
- data/spec/config_spec.rb +48 -0
- data/spec/database_rollback_spec.rb +45 -0
- data/spec/my_model_spec.rb +36 -0
- data/spec/recorder_spec.rb +125 -0
- data/spec/rollbacker_change_spec.rb +19 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/status_spec.rb +44 -0
- data/spec/support/db_setup.rb +51 -0
- data/spec/support/model_setup.rb +29 -0
- data/spec/support/transactional_specs.rb +17 -0
- data/spec/user_spec.rb +25 -0
- metadata +142 -0
@@ -0,0 +1,74 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require 'rollbacker/config'
|
3
|
+
|
4
|
+
describe Rollbacker::ChangeValidator do
|
5
|
+
describe ":destroy" do
|
6
|
+
let(:action) { :destroy }
|
7
|
+
it "should not be valid if the model is a new record" do
|
8
|
+
model = Model.new
|
9
|
+
config = Rollbacker::Config.new(action)
|
10
|
+
validator = Rollbacker::ChangeValidator.new(action, config.options, model)
|
11
|
+
model.should be_new_record
|
12
|
+
validator.changes.should == {}
|
13
|
+
validator.should_not be_valid
|
14
|
+
end
|
15
|
+
it "should be valid if the model is persisted" do
|
16
|
+
model = Model.create
|
17
|
+
config = Rollbacker::Config.new(action)
|
18
|
+
validator = Rollbacker::ChangeValidator.new(action, config.options, model)
|
19
|
+
model.should be_persisted
|
20
|
+
validator.changes.should == {}
|
21
|
+
validator.should be_valid
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
[:create, :update].each do |action|
|
26
|
+
describe ":#{ action }" do
|
27
|
+
it "should be invalid if model has no change" do
|
28
|
+
model = Model.new
|
29
|
+
config = Rollbacker::Config.new(action)
|
30
|
+
validator = Rollbacker::ChangeValidator.new(action, config.options, model)
|
31
|
+
validator.changes.should == {}
|
32
|
+
validator.should_not be_valid
|
33
|
+
end
|
34
|
+
it "should be valid if model changed" do
|
35
|
+
model = Model.new(name: "Name")
|
36
|
+
config = Rollbacker::Config.new(action)
|
37
|
+
validator = Rollbacker::ChangeValidator.new(action, config.options, model)
|
38
|
+
model.should be_changed
|
39
|
+
validator.changes.should == {'name' => [nil, 'Name']}
|
40
|
+
validator.should be_valid
|
41
|
+
end
|
42
|
+
it "should ignore fields from :except config" do
|
43
|
+
model = Model.new(name: "Name", value: "Value")
|
44
|
+
config = Rollbacker::Config.new(action, :except => :name)
|
45
|
+
validator = Rollbacker::ChangeValidator.new(action, config.options, model)
|
46
|
+
model.should be_changed
|
47
|
+
model.changes.keys.should be_include('name')
|
48
|
+
model.changes.keys.should be_include('value')
|
49
|
+
validator.changes.should == {'value' => [nil, 'Value']}
|
50
|
+
end
|
51
|
+
it "should select changes from :only config" do
|
52
|
+
model = Model.new(name: "Name", value: "Value")
|
53
|
+
config = Rollbacker::Config.new(action, :only => :value)
|
54
|
+
validator = Rollbacker::ChangeValidator.new(action, config.options, model)
|
55
|
+
model.should be_changed
|
56
|
+
model.changes.keys.should be_include('name')
|
57
|
+
model.changes.keys.should be_include('value')
|
58
|
+
validator.changes.should == {'value' => [nil, 'Value']}
|
59
|
+
end
|
60
|
+
it "should be able to merge changes from current rollbacker_change record" do
|
61
|
+
model = Model.new(name: "Newer")
|
62
|
+
config = Rollbacker::Config.new(action)
|
63
|
+
validator = Rollbacker::ChangeValidator.new(action, config.options, model)
|
64
|
+
model.should be_changed
|
65
|
+
model.changes.keys.should be_include('name')
|
66
|
+
model.changes.keys.should_not be_include('value')
|
67
|
+
validator.changes({
|
68
|
+
'value' => [nil, 'Old Value'],
|
69
|
+
'name' => [nil, 'Old Name']
|
70
|
+
}).should == {'name' => [nil, 'Newer'], 'value'=> [nil, 'Old Value']}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/spec/config_spec.rb
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require 'rollbacker/config'
|
3
|
+
|
4
|
+
describe Rollbacker::Config do
|
5
|
+
|
6
|
+
describe 'Configuration' do
|
7
|
+
it "should parse actions and options from a config array" do
|
8
|
+
config = Rollbacker::Config.new(:create, 'update', {:only => :username})
|
9
|
+
config.actions.should_not be_nil
|
10
|
+
config.options.should_not be_nil
|
11
|
+
config.actions.should have(2).items
|
12
|
+
config.actions.should =~ [:create, :update]
|
13
|
+
config.options.should == {:only => ["username"], :except => []}
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should parse actions and options from a config array when options are absent" do
|
17
|
+
config = Rollbacker::Config.new(:create, 'update')
|
18
|
+
config.actions.should_not be_nil
|
19
|
+
config.actions.should have(2).items
|
20
|
+
config.actions.should =~ [:create, :update]
|
21
|
+
config.options.should == {:only => [], :except => []}
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should parse actions" do
|
25
|
+
config = Rollbacker::Config.new(:create)
|
26
|
+
config.actions.should_not be_nil
|
27
|
+
config.actions.should have(1).item
|
28
|
+
config.actions.should =~ [:create]
|
29
|
+
config.options.should == {:only => [], :except => []}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe 'Configuration Validation' do
|
34
|
+
it "should raise a Rollbacker::Error if no action is specified" do
|
35
|
+
lambda {
|
36
|
+
Rollbacker::Config.new
|
37
|
+
}.should raise_error(Rollbacker::Error)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should raise a Rollbacker::Error if an invalid action is specified" do
|
41
|
+
lambda {
|
42
|
+
Rollbacker::Config.new(:create, :view)
|
43
|
+
}.should raise_error(Rollbacker::Error)
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require 'rollbacker/user'
|
3
|
+
require 'rollbacker/status'
|
4
|
+
|
5
|
+
describe Rollbacker::DatabaseRollback do
|
6
|
+
include Rollbacker::Status
|
7
|
+
|
8
|
+
before(:each) do
|
9
|
+
Thread.current[:rollbacker_disabled] = nil
|
10
|
+
@user = Rollbacker::User.current_user = User.create
|
11
|
+
end
|
12
|
+
|
13
|
+
[:create, :update, :destroy].each do |action|
|
14
|
+
it "should respond with around_#{action}" do
|
15
|
+
model = Model.new(name: 'name')
|
16
|
+
config = Rollbacker::Config.new(action)
|
17
|
+
callback = Rollbacker::DatabaseRollback.new(config.options)
|
18
|
+
callback.should respond_to("around_#{action}")
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should rollback using without_rollbacker" do
|
23
|
+
model = Model.new
|
24
|
+
model.should_receive(:"_rollbacker_action=").with(:create).and_return(:create)
|
25
|
+
config = Rollbacker::Config.new('create')
|
26
|
+
callback = Rollbacker::DatabaseRollback.new(config.options)
|
27
|
+
|
28
|
+
lambda {
|
29
|
+
without_rollbacker do
|
30
|
+
callback.send :around_create, model
|
31
|
+
end
|
32
|
+
}.should_not raise_exception(ActiveRecord::Rollback)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should rollback as default with a object with changes" do
|
36
|
+
model = Model.new(name: 'name')
|
37
|
+
model.should_receive(:"_rollbacker_action=").with(:create).and_return(:create)
|
38
|
+
config = Rollbacker::Config.new('create')
|
39
|
+
callback = Rollbacker::DatabaseRollback.new(config.options)
|
40
|
+
|
41
|
+
lambda {
|
42
|
+
callback.send :around_create, model
|
43
|
+
}.should raise_exception(ActiveRecord::Rollback)
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
describe MyModel do
|
4
|
+
let(:model) { MyModel.new(name: 'Name', value: 'Value') }
|
5
|
+
|
6
|
+
context "new record" do
|
7
|
+
it 'add create callback to history' do
|
8
|
+
lambda {
|
9
|
+
model.save
|
10
|
+
}.should_not change(MyModel, :count)
|
11
|
+
model.history.should == ['after_rollback_on_create']
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
context "persisted record" do
|
16
|
+
before(:each) do
|
17
|
+
model.skip_before_create = true
|
18
|
+
model.save
|
19
|
+
end
|
20
|
+
it 'add update callback to history' do
|
21
|
+
lambda {
|
22
|
+
model.update_attribute(:name, 'Newer')
|
23
|
+
}.should_not change(MyModel, :count)
|
24
|
+
model.history.should == ['after_rollback_on_update']
|
25
|
+
end
|
26
|
+
pending 'add destroy callback to history' do
|
27
|
+
lambda {
|
28
|
+
model.destroy
|
29
|
+
}.should_not change(MyModel, :count)
|
30
|
+
# Currently the result of this test is:
|
31
|
+
# model.history.should == ['after_rollback_on_update']
|
32
|
+
# See more details here: https://github.com/rails/rails/issues/7640
|
33
|
+
model.history.should == ['after_rollback_on_destroy']
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require 'rollbacker/user'
|
3
|
+
|
4
|
+
describe Rollbacker::Recorder do
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
@user = Rollbacker::User.current_user = User.create
|
8
|
+
end
|
9
|
+
|
10
|
+
[:create, :update].each do |action|
|
11
|
+
it "should NOT be created an rollbacker_change record for #{action} actions if no changes" do
|
12
|
+
model = Model.new
|
13
|
+
model.stub(:_rollbacker_action).and_return(action)
|
14
|
+
model.save if action.eql?(:update)
|
15
|
+
|
16
|
+
config = Rollbacker::Config.new(action)
|
17
|
+
# recorder = Rollbacker::Recorder.new(action, config.options)
|
18
|
+
recorder = Rollbacker::Recorder.new(config.options)
|
19
|
+
|
20
|
+
lambda {
|
21
|
+
recorder.send "after_rollback", model
|
22
|
+
}.should_not change(RollbackerChange, :count)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
[:destroy, :update].each do |action|
|
27
|
+
it "should NOT be created change record for #{action} actions if model is a new record" do
|
28
|
+
model = Model.new
|
29
|
+
model.stub(:_rollbacker_action).and_return(action)
|
30
|
+
|
31
|
+
config = Rollbacker::Config.new(action)
|
32
|
+
# recorder = Rollbacker::Recorder.new(action, config.options)
|
33
|
+
recorder = Rollbacker::Recorder.new(config.options)
|
34
|
+
|
35
|
+
lambda {
|
36
|
+
recorder.send "after_rollback", model
|
37
|
+
}.should_not change(RollbackerChange, :count)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "on :create" do
|
42
|
+
let(:action) { :create }
|
43
|
+
it "should be create the change record after model rollback" do
|
44
|
+
model = Model.new(name: "Changed")
|
45
|
+
model.stub(:_rollbacker_action).and_return(action)
|
46
|
+
config = Rollbacker::Config.new(action)
|
47
|
+
|
48
|
+
# recorder = Rollbacker::Recorder.new(action, config.options)
|
49
|
+
recorder = Rollbacker::Recorder.new(config.options)
|
50
|
+
lambda {
|
51
|
+
recorder.send "after_rollback", model
|
52
|
+
}.should change(RollbackerChange, :count).by(1)
|
53
|
+
|
54
|
+
change_record = RollbackerChange.last
|
55
|
+
change_record.action.should == action.to_s
|
56
|
+
change_record.rollbackable_id.should == model.id
|
57
|
+
change_record.rollbackable_type.should == model.class.to_s
|
58
|
+
change_record.user_id.should == @user.id
|
59
|
+
change_record.user_type.should == @user.class.to_s
|
60
|
+
change_record.rollbacked_changes.should == {'name' => [nil, 'Changed'] }
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "on :update" do
|
66
|
+
let(:action) { :update }
|
67
|
+
let(:model) { Model.create(name: "Name") }
|
68
|
+
it "should create the change record" do
|
69
|
+
model.name = 'Changed'
|
70
|
+
model.stub(:_rollbacker_action).and_return(action)
|
71
|
+
config = Rollbacker::Config.new(action)
|
72
|
+
# recorder = Rollbacker::Recorder.new(action, config.options)
|
73
|
+
recorder = Rollbacker::Recorder.new(config.options)
|
74
|
+
lambda {
|
75
|
+
recorder.send "after_rollback", model
|
76
|
+
}.should change(RollbackerChange, :count).by(1)
|
77
|
+
|
78
|
+
change_record = RollbackerChange.last
|
79
|
+
change_record.action.should == action.to_s
|
80
|
+
change_record.rollbackable_id.should == model.id
|
81
|
+
change_record.rollbackable_type.should== model.class.to_s
|
82
|
+
change_record.user_id.should == @user.id
|
83
|
+
change_record.user_type.should == @user.class.to_s
|
84
|
+
change_record.rollbacked_changes.should == {'name' => ['Name', 'Changed'] }
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should only update rollbacked_changes field if the change record already exist" do
|
88
|
+
edit1 = RollbackerChange.create(rollbackable: model, user: @user, action: action, rollbacked_changes: {'name'=>[nil, 'Name']})
|
89
|
+
# Update
|
90
|
+
model.name = 'Changed'
|
91
|
+
model.stub(:_rollbacker_action).and_return(action)
|
92
|
+
config = Rollbacker::Config.new(action)
|
93
|
+
# recorder = Rollbacker::Recorder.new(action, config.options)
|
94
|
+
recorder = Rollbacker::Recorder.new(config.options)
|
95
|
+
|
96
|
+
lambda {
|
97
|
+
recorder.send "after_rollback", model
|
98
|
+
}.should_not change(RollbackerChange, :count)
|
99
|
+
|
100
|
+
edit2 = RollbackerChange.last
|
101
|
+
edit1.id.should == edit2.id
|
102
|
+
edit2.action.should == action.to_s
|
103
|
+
edit2.rollbackable_id.should == model.id
|
104
|
+
edit2.rollbackable_type.should == model.class.to_s
|
105
|
+
edit2.user_id.should == @user.id
|
106
|
+
edit2.user_type.should == @user.class.to_s
|
107
|
+
edit2.rollbacked_changes.should == {'name' => ['Name', 'Changed'] }
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'should pass the model, record, user, and action to any supplied block' do
|
112
|
+
model = Model.create
|
113
|
+
model.stub(:_rollbacker_action).and_return(:create)
|
114
|
+
config = Rollbacker::Config.new(:create)
|
115
|
+
# recorder = Rollbacker::Recorder.new(:create, config.options) do |model, record, user, action|
|
116
|
+
recorder = Rollbacker::Recorder.new(config.options) do |model, record, user, action|
|
117
|
+
model.should == model
|
118
|
+
record.should be_is_a(RollbackerChange)
|
119
|
+
user.should == @user
|
120
|
+
action.should == :create
|
121
|
+
end
|
122
|
+
recorder.after_rollback(model)
|
123
|
+
end
|
124
|
+
|
125
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require 'rollbacker/rollbacker_change'
|
3
|
+
|
4
|
+
describe RollbackerChange do
|
5
|
+
before(:each) do
|
6
|
+
@rollbackable = Model.create
|
7
|
+
@user = User.create
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'should provide access to the rollbacked model object' do
|
11
|
+
record = RollbackerChange.create(:rollbackable => @rollbackable, :user => @user, :action => :create)
|
12
|
+
record.rollbackable.should == @rollbackable
|
13
|
+
end
|
14
|
+
it 'should provide access to the user associated with the rollbacker_change' do
|
15
|
+
record = RollbackerChange.create(:rollbackable => @rollbackable, :user => @user, :action => :create)
|
16
|
+
record.user.should == @user
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'rollbacker'
|
3
|
+
|
4
|
+
# Requires supporting files with custom matchers and macros, etc,
|
5
|
+
# in ./support/ and its subdirectories.
|
6
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
7
|
+
|
8
|
+
RSpec.configure do |config|
|
9
|
+
config.include TransactionalSpecs
|
10
|
+
# RSpec uses it's own mocking framework by default. If you prefer to
|
11
|
+
# use mocha, flexmock or RR, uncomment the appropriate line:
|
12
|
+
#
|
13
|
+
# config.mock_with :mocha
|
14
|
+
# config.mock_with :flexmock
|
15
|
+
# config.mock_with :rr
|
16
|
+
end
|
data/spec/status_spec.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require 'rollbacker/status'
|
3
|
+
|
4
|
+
describe Rollbacker::Status do
|
5
|
+
it "should be enabled if set to enabled" do
|
6
|
+
obj = Class.new { include Rollbacker::Status }.new
|
7
|
+
obj.enable_rollbacker!
|
8
|
+
obj.should be_rollbacker_enabled
|
9
|
+
obj.should_not be_rollbacker_disabled
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should be disabled if set to disabled" do
|
13
|
+
obj = Class.new { include Rollbacker::Status }.new
|
14
|
+
obj.disable_rollbacker!
|
15
|
+
obj.should_not be_rollbacker_enabled
|
16
|
+
obj.should be_rollbacker_disabled
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should allow auditing as a specified user for a block of code" do
|
20
|
+
obj = Class.new { include Rollbacker::Status }.new
|
21
|
+
user1 = "user1"
|
22
|
+
user2 = "user2"
|
23
|
+
Rollbacker::User.current_user = user1
|
24
|
+
|
25
|
+
obj.rollbacker_as(user2) { Rollbacker::User.current_user.should == user2 }
|
26
|
+
Rollbacker::User.current_user.should == user1
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should allow a block of code to be executed with rollbacker disabled" do
|
30
|
+
obj = Class.new { include Rollbacker::Status }.new
|
31
|
+
obj.enable_rollbacker!
|
32
|
+
obj.should be_rollbacker_enabled
|
33
|
+
obj.without_rollbacker { obj.should be_rollbacker_disabled }
|
34
|
+
obj.should be_rollbacker_enabled
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should allow a block of code to be executed with rollbacker enabled" do
|
38
|
+
obj = Class.new { include Rollbacker::Status }.new
|
39
|
+
obj.disable_rollbacker!
|
40
|
+
obj.should be_rollbacker_disabled
|
41
|
+
obj.with_rollbacker { obj.should be_rollbacker_enabled }
|
42
|
+
obj.should be_rollbacker_disabled
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'active_support/core_ext'
|
2
|
+
require 'active_record'
|
3
|
+
require 'generators/rollbacker/migration/templates/migration'
|
4
|
+
require 'fileutils'
|
5
|
+
|
6
|
+
tmpdir = File.join(File.dirname(__FILE__), '..', '..', 'tmp')
|
7
|
+
FileUtils.mkdir(tmpdir) unless File.exist?(tmpdir)
|
8
|
+
test_db = File.join(tmpdir, 'test.db')
|
9
|
+
|
10
|
+
connection_spec = {
|
11
|
+
:adapter => 'sqlite3',
|
12
|
+
:database => test_db
|
13
|
+
}
|
14
|
+
|
15
|
+
# Delete any existing instance of the test database
|
16
|
+
FileUtils.rm test_db, :force => true
|
17
|
+
|
18
|
+
# Create a new test database
|
19
|
+
ActiveRecord::Base.establish_connection(connection_spec)
|
20
|
+
|
21
|
+
# ActiveRecord::Base.connection.initialize_schema_migrations_table
|
22
|
+
|
23
|
+
class CreateUser < ActiveRecord::Migration
|
24
|
+
def self.up
|
25
|
+
create_table :users, :force => true do |t|
|
26
|
+
t.column :username, :string
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.down
|
31
|
+
drop_table :users
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
class CreateModel < ActiveRecord::Migration
|
36
|
+
def self.up
|
37
|
+
create_table :models, :force => true do |t|
|
38
|
+
t.column :name, :string
|
39
|
+
t.column :value, :string
|
40
|
+
t.column :user_id, :integer
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.down
|
45
|
+
drop_table :models
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
CreateUser.up
|
50
|
+
CreateModel.up
|
51
|
+
CreateRollbackerChangesTable.up
|
@@ -0,0 +1,29 @@
|
|
1
|
+
class User < ActiveRecord::Base; end
|
2
|
+
class Model < ActiveRecord::Base
|
3
|
+
belongs_to :user
|
4
|
+
end
|
5
|
+
|
6
|
+
class MyModel < ActiveRecord::Base
|
7
|
+
include ActiveRecord::Transactions::ClassMethods
|
8
|
+
self.table_name = 'models'
|
9
|
+
|
10
|
+
before_create :raise_rollback!, :unless => :skip_before_create
|
11
|
+
before_destroy :raise_rollback!
|
12
|
+
before_update :raise_rollback!
|
13
|
+
after_rollback(:on => :create){|record| record.send(:do_after_rollback, :create)}
|
14
|
+
after_rollback(:on => :update){|record| record.send(:do_after_rollback, :update)}
|
15
|
+
after_rollback(:on => :destroy){|record| record.send(:do_after_rollback, :destroy)}
|
16
|
+
attr_accessor :skip_before_create
|
17
|
+
|
18
|
+
def history
|
19
|
+
@history ||= []
|
20
|
+
end
|
21
|
+
private
|
22
|
+
def raise_rollback!
|
23
|
+
raise ActiveRecord::Rollback
|
24
|
+
end
|
25
|
+
|
26
|
+
def do_after_rollback(on)
|
27
|
+
history << "after_rollback_on_#{on}"
|
28
|
+
end
|
29
|
+
end
|
data/spec/user_spec.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
require 'rollbacker/user'
|
3
|
+
|
4
|
+
describe Rollbacker::User do
|
5
|
+
it "should return the same user that's set on the same thread" do
|
6
|
+
user = "user"
|
7
|
+
Rollbacker::User.current_user = user
|
8
|
+
Rollbacker::User.current_user.should == user
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should not return the same user from a different thread" do
|
12
|
+
user = "user"
|
13
|
+
user2 = "user2"
|
14
|
+
|
15
|
+
Rollbacker::User.current_user = user
|
16
|
+
|
17
|
+
Thread.new do
|
18
|
+
Rollbacker::User.current_user.should be_nil
|
19
|
+
Rollbacker::User.current_user = user2
|
20
|
+
Rollbacker::User.current_user.should == user2
|
21
|
+
end
|
22
|
+
|
23
|
+
Rollbacker::User.current_user.should == user
|
24
|
+
end
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,142 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: rollbacker
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Marcos G. Zimmermann
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-09-17 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activerecord
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '3.0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '3.0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: rspec
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :development
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: sqlite3-ruby
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: Rollbacker allows you to declaratively specify what CRUD operations should
|
63
|
+
be audited. The changes of objects are added to a queue where the auditor can approve
|
64
|
+
and reject those changes.
|
65
|
+
email:
|
66
|
+
- mgzmaster@gmail.com
|
67
|
+
executables: []
|
68
|
+
extensions: []
|
69
|
+
extra_rdoc_files: []
|
70
|
+
files:
|
71
|
+
- .gitignore
|
72
|
+
- Gemfile
|
73
|
+
- LICENSE
|
74
|
+
- README.md
|
75
|
+
- Rakefile
|
76
|
+
- init.rb
|
77
|
+
- lib/generators/rollbacker.rb
|
78
|
+
- lib/generators/rollbacker/migration/migration_generator.rb
|
79
|
+
- lib/generators/rollbacker/migration/templates/migration.rb
|
80
|
+
- lib/rollbacker.rb
|
81
|
+
- lib/rollbacker/base.rb
|
82
|
+
- lib/rollbacker/change_validator.rb
|
83
|
+
- lib/rollbacker/config.rb
|
84
|
+
- lib/rollbacker/database_rollback.rb
|
85
|
+
- lib/rollbacker/recorder.rb
|
86
|
+
- lib/rollbacker/rollbacker_change.rb
|
87
|
+
- lib/rollbacker/spec_helpers.rb
|
88
|
+
- lib/rollbacker/status.rb
|
89
|
+
- lib/rollbacker/user.rb
|
90
|
+
- lib/rollbacker/version.rb
|
91
|
+
- rollbacker.gemspec
|
92
|
+
- spec/base_spec.rb
|
93
|
+
- spec/change_validator_spec.rb
|
94
|
+
- spec/config_spec.rb
|
95
|
+
- spec/database_rollback_spec.rb
|
96
|
+
- spec/my_model_spec.rb
|
97
|
+
- spec/recorder_spec.rb
|
98
|
+
- spec/rollbacker_change_spec.rb
|
99
|
+
- spec/spec_helper.rb
|
100
|
+
- spec/status_spec.rb
|
101
|
+
- spec/support/db_setup.rb
|
102
|
+
- spec/support/model_setup.rb
|
103
|
+
- spec/support/transactional_specs.rb
|
104
|
+
- spec/user_spec.rb
|
105
|
+
homepage: http://github.com/marcosgz/rollbacker
|
106
|
+
licenses: []
|
107
|
+
post_install_message:
|
108
|
+
rdoc_options: []
|
109
|
+
require_paths:
|
110
|
+
- lib
|
111
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
none: false
|
113
|
+
requirements:
|
114
|
+
- - ! '>='
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
118
|
+
none: false
|
119
|
+
requirements:
|
120
|
+
- - ! '>='
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: '0'
|
123
|
+
requirements: []
|
124
|
+
rubyforge_project:
|
125
|
+
rubygems_version: 1.8.24
|
126
|
+
signing_key:
|
127
|
+
specification_version: 3
|
128
|
+
summary: Rollbacker is a manage tool for auditing changes to your ActiveRecord
|
129
|
+
test_files:
|
130
|
+
- spec/base_spec.rb
|
131
|
+
- spec/change_validator_spec.rb
|
132
|
+
- spec/config_spec.rb
|
133
|
+
- spec/database_rollback_spec.rb
|
134
|
+
- spec/my_model_spec.rb
|
135
|
+
- spec/recorder_spec.rb
|
136
|
+
- spec/rollbacker_change_spec.rb
|
137
|
+
- spec/spec_helper.rb
|
138
|
+
- spec/status_spec.rb
|
139
|
+
- spec/support/db_setup.rb
|
140
|
+
- spec/support/model_setup.rb
|
141
|
+
- spec/support/transactional_specs.rb
|
142
|
+
- spec/user_spec.rb
|