acts_as_revisionable 1.0.3
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 +1 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +56 -0
- data/Rakefile +47 -0
- data/VERSION +1 -0
- data/acts_as_revisionable.gemspec +66 -0
- data/lib/acts_as_revisionable/revision_record.rb +227 -0
- data/lib/acts_as_revisionable.rb +193 -0
- data/spec/acts_as_revisionable_spec.rb +176 -0
- data/spec/full_spec.rb +448 -0
- data/spec/revision_record_spec.rb +428 -0
- data/spec/spec_helper.rb +23 -0
- metadata +141 -0
@@ -0,0 +1,176 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe ActsAsRevisionable do
|
4
|
+
|
5
|
+
before :all do
|
6
|
+
ActsAsRevisionable::Test.create_database
|
7
|
+
end
|
8
|
+
|
9
|
+
after :all do
|
10
|
+
ActsAsRevisionable::Test.delete_database
|
11
|
+
end
|
12
|
+
|
13
|
+
class TestRevisionableModel
|
14
|
+
include ActsAsRevisionable
|
15
|
+
|
16
|
+
attr_accessor :id
|
17
|
+
|
18
|
+
def update
|
19
|
+
really_update
|
20
|
+
end
|
21
|
+
|
22
|
+
def really_update
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.has_many (name, options)
|
26
|
+
@associations ||= {}
|
27
|
+
@associations[name] = options
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.associations
|
31
|
+
@associations
|
32
|
+
end
|
33
|
+
|
34
|
+
private :update
|
35
|
+
|
36
|
+
acts_as_revisionable :limit => 10, :on_update => true, :associations => [:one, {:two => :two_1, :three => [:three_1, :three_2]}, {:four => :four_1}], :encoding => :encoding
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should be able to inject revisionable behavior onto ActiveRecord::Base" do
|
40
|
+
ActiveRecord::Base.included_modules.should include(ActsAsRevisionable)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should add as has_many :record_revisions association" do
|
44
|
+
TestRevisionableModel.associations[:revision_records].should == {:as => :revisionable, :dependent => :destroy, :order=>"revision DESC", :class_name => "ActsAsRevisionable::RevisionRecord"}
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should parse the revisionable associations" do
|
48
|
+
TestRevisionableModel.revisionable_associations.should == {:one => true, :two => {:two_1 => true}, :three => {:three_1 => true, :three_2 => true}, :four => {:four_1 => true}}
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should handle storing revisions in a block" do
|
52
|
+
record = TestRevisionableModel.new
|
53
|
+
record.id = 1
|
54
|
+
record.stub!(:new_record?).and_return(nil)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should not store revisions for a new record" do
|
58
|
+
record = TestRevisionableModel.new
|
59
|
+
record.stub!(:new_record?).and_return(true)
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should handle storing revisions" do
|
63
|
+
record = TestRevisionableModel.new
|
64
|
+
record.id = 1
|
65
|
+
record.stub!(:new_record?).and_return(nil)
|
66
|
+
record.stub!(:errors).and_return([])
|
67
|
+
read_only_record = TestRevisionableModel.new
|
68
|
+
TestRevisionableModel.should_receive(:find).with(1, :readonly => true).and_return(read_only_record)
|
69
|
+
revision = mock(:revision)
|
70
|
+
ActsAsRevisionable::RevisionRecord.should_receive(:transaction).and_yield
|
71
|
+
read_only_record.should_receive(:create_revision!).and_return(revision)
|
72
|
+
record.should_receive(:truncate_revisions!).with()
|
73
|
+
record.should_receive(:really_update)
|
74
|
+
|
75
|
+
record.store_revision do
|
76
|
+
record.send(:update)
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should delete a revision if the update fails" do
|
81
|
+
record = TestRevisionableModel.new
|
82
|
+
record.id = 1
|
83
|
+
record.stub!(:new_record?).and_return(nil)
|
84
|
+
record.stub!(:errors).and_return([])
|
85
|
+
read_only_record = TestRevisionableModel.new
|
86
|
+
TestRevisionableModel.should_receive(:find).with(1, :readonly => true).and_return(read_only_record)
|
87
|
+
revision = mock(:revision)
|
88
|
+
ActsAsRevisionable::RevisionRecord.should_receive(:transaction).and_yield
|
89
|
+
read_only_record.should_receive(:create_revision!).and_return(revision)
|
90
|
+
record.should_receive(:truncate_revisions!).with()
|
91
|
+
record.should_receive(:really_update).and_raise("update failed")
|
92
|
+
revision.should_receive(:destroy)
|
93
|
+
|
94
|
+
begin
|
95
|
+
record.store_revision do
|
96
|
+
record.send(:update)
|
97
|
+
end
|
98
|
+
rescue
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should not error on deleting a revision if the update fails" do
|
103
|
+
record = TestRevisionableModel.new
|
104
|
+
record.id = 1
|
105
|
+
record.stub!(:new_record?).and_return(nil)
|
106
|
+
record.stub!(:errors).and_return([:error])
|
107
|
+
read_only_record = TestRevisionableModel.new
|
108
|
+
TestRevisionableModel.should_receive(:find).with(1, :readonly => true).and_return(read_only_record)
|
109
|
+
revision = mock(:revision)
|
110
|
+
ActsAsRevisionable::RevisionRecord.should_receive(:transaction).and_yield
|
111
|
+
read_only_record.should_receive(:create_revision!).and_return(revision)
|
112
|
+
record.should_receive(:truncate_revisions!).with()
|
113
|
+
record.should_receive(:update).and_raise("update failed")
|
114
|
+
revision.should_receive(:destroy).and_raise("destroy failed")
|
115
|
+
|
116
|
+
record.store_revision do
|
117
|
+
record.send(:update) rescue nil
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should be able to create a revision record" do
|
122
|
+
record = TestRevisionableModel.new
|
123
|
+
revision = mock(:revision)
|
124
|
+
ActsAsRevisionable::RevisionRecord.should_receive(:new).with(record, :encoding).and_return(revision)
|
125
|
+
revision.should_receive(:save!)
|
126
|
+
record.create_revision!.should == revision
|
127
|
+
end
|
128
|
+
|
129
|
+
it "should create a revision entry when a model is updated if :on_update is true" do
|
130
|
+
record = TestRevisionableModel.new
|
131
|
+
record.should_receive(:new_record?).and_return(false)
|
132
|
+
record.should_receive(:errors).and_return([])
|
133
|
+
record.should_receive(:really_update).and_return(:retval)
|
134
|
+
record.send(:update).should == :retval
|
135
|
+
end
|
136
|
+
|
137
|
+
it "should not create a revision entry if revisioning is disabled" do
|
138
|
+
record = TestRevisionableModel.new
|
139
|
+
record.stub!(:new_record?).and_return(nil)
|
140
|
+
TestRevisionableModel.should_not_receive(:find)
|
141
|
+
ActsAsRevisionable::RevisionRecord.should_not_receive(:transaction)
|
142
|
+
record.should_not_receive(:create_revision!)
|
143
|
+
record.should_not_receive(:truncate_revisions!)
|
144
|
+
record.should_receive(:update)
|
145
|
+
|
146
|
+
record.disable_revisioning do
|
147
|
+
record.store_revision do
|
148
|
+
record.send(:update)
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
it "should truncate the revisions" do
|
154
|
+
record = TestRevisionableModel.new
|
155
|
+
record.stub!(:id).and_return(1)
|
156
|
+
ActsAsRevisionable::RevisionRecord.should_receive(:truncate_revisions).with(TestRevisionableModel, 1, {:limit => 20, :minimum_age => 2.weeks})
|
157
|
+
record.truncate_revisions!(:limit => 20, :minimum_age => 2.weeks)
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should be able to restore a revision by id and revision" do
|
161
|
+
revision = mock(:revision)
|
162
|
+
record = mock(:record)
|
163
|
+
ActsAsRevisionable::RevisionRecord.should_receive(:find_revision).with(TestRevisionableModel, 1, 5).and_return(revision)
|
164
|
+
revision.should_receive(:restore).and_return(record)
|
165
|
+
TestRevisionableModel.restore_revision(1, 5).should == record
|
166
|
+
end
|
167
|
+
|
168
|
+
it "should be able to restore a revision by id and revision and save it" do
|
169
|
+
record = mock(:record)
|
170
|
+
TestRevisionableModel.should_receive(:restore_revision).with(1, 5).and_return(record)
|
171
|
+
record.should_receive(:store_revision).and_yield
|
172
|
+
TestRevisionableModel.should_receive(:save_restorable_associations).with(record, TestRevisionableModel.revisionable_associations)
|
173
|
+
TestRevisionableModel.restore_revision!(1, 5).should == record
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
data/spec/full_spec.rb
ADDED
@@ -0,0 +1,448 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "ActsAsRevisionable Full Test" do
|
4
|
+
|
5
|
+
before(:all) do
|
6
|
+
ActsAsRevisionable::Test.create_database
|
7
|
+
|
8
|
+
ActiveRecord::Base.store_full_sti_class = true
|
9
|
+
|
10
|
+
class RevisionableTestSubThing < ActiveRecord::Base
|
11
|
+
connection.create_table(:revisionable_test_sub_things) do |t|
|
12
|
+
t.column :name, :string
|
13
|
+
t.column :revisionable_test_many_thing_id, :integer
|
14
|
+
end unless table_exists?
|
15
|
+
end
|
16
|
+
|
17
|
+
class RevisionableTestManyThing < ActiveRecord::Base
|
18
|
+
connection.create_table(:revisionable_test_many_things) do |t|
|
19
|
+
t.column :name, :string
|
20
|
+
t.column :revisionable_test_model_id, :integer
|
21
|
+
end unless table_exists?
|
22
|
+
|
23
|
+
has_many :sub_things, :class_name => 'RevisionableTestSubThing'
|
24
|
+
end
|
25
|
+
|
26
|
+
class RevisionableTestManyOtherThing < ActiveRecord::Base
|
27
|
+
connection.create_table(:revisionable_test_many_other_things) do |t|
|
28
|
+
t.column :name, :string
|
29
|
+
t.column :revisionable_test_model_id, :integer
|
30
|
+
end unless table_exists?
|
31
|
+
end
|
32
|
+
|
33
|
+
class RevisionableTestOneThing < ActiveRecord::Base
|
34
|
+
connection.create_table(:revisionable_test_one_things) do |t|
|
35
|
+
t.column :name, :string
|
36
|
+
t.column :revisionable_test_model_id, :integer
|
37
|
+
end unless table_exists?
|
38
|
+
end
|
39
|
+
|
40
|
+
class NonRevisionableTestModel < ActiveRecord::Base
|
41
|
+
connection.create_table(:non_revisionable_test_models) do |t|
|
42
|
+
t.column :name, :string
|
43
|
+
end unless table_exists?
|
44
|
+
end
|
45
|
+
|
46
|
+
class NonRevisionableTestModelsRevisionableTestModel < ActiveRecord::Base
|
47
|
+
connection.create_table(:non_revisionable_test_models_revisionable_test_models, :id => false) do |t|
|
48
|
+
t.column :non_revisionable_test_model_id, :integer
|
49
|
+
t.column :revisionable_test_model_id, :integer
|
50
|
+
end unless table_exists?
|
51
|
+
end
|
52
|
+
|
53
|
+
class RevisionableTestModel < ActiveRecord::Base
|
54
|
+
connection.create_table(:revisionable_test_models) do |t|
|
55
|
+
t.column :name, :string
|
56
|
+
t.column :secret, :integer
|
57
|
+
end unless table_exists?
|
58
|
+
|
59
|
+
has_many :many_things, :class_name => 'RevisionableTestManyThing', :dependent => :destroy
|
60
|
+
has_many :many_other_things, :class_name => 'RevisionableTestManyOtherThing', :dependent => :destroy
|
61
|
+
has_one :one_thing, :class_name => 'RevisionableTestOneThing'
|
62
|
+
has_and_belongs_to_many :non_revisionable_test_models
|
63
|
+
|
64
|
+
attr_protected :secret
|
65
|
+
|
66
|
+
acts_as_revisionable :limit => 3, :associations => [:one_thing, :non_revisionable_test_models, {:many_things => :sub_things}]
|
67
|
+
|
68
|
+
def set_secret (val)
|
69
|
+
self.secret = val
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def secret= (val)
|
75
|
+
self[:secret] = val
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
module ActsAsRevisionable
|
80
|
+
class RevisionableNamespaceModel < ActiveRecord::Base
|
81
|
+
connection.create_table(:revisionable_namespace_models) do |t|
|
82
|
+
t.column :name, :string
|
83
|
+
t.column :type_name, :string
|
84
|
+
end unless table_exists?
|
85
|
+
|
86
|
+
set_inheritance_column :type_name
|
87
|
+
acts_as_revisionable :dependent => :keep, :encoding => :xml
|
88
|
+
end
|
89
|
+
|
90
|
+
class RevisionableSubclassModel < RevisionableNamespaceModel
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
after :all do
|
96
|
+
ActsAsRevisionable::Test.delete_database
|
97
|
+
end
|
98
|
+
|
99
|
+
before :each do
|
100
|
+
RevisionableTestModel.delete_all
|
101
|
+
RevisionableTestManyThing.delete_all
|
102
|
+
RevisionableTestManyOtherThing.delete_all
|
103
|
+
RevisionableTestSubThing.delete_all
|
104
|
+
RevisionableTestOneThing.delete_all
|
105
|
+
NonRevisionableTestModelsRevisionableTestModel.delete_all
|
106
|
+
NonRevisionableTestModel.delete_all
|
107
|
+
ActsAsRevisionable::RevisionRecord.delete_all
|
108
|
+
ActsAsRevisionable::RevisionableNamespaceModel.delete_all
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should only store revisions in a store revision block if :on_update is not true" do
|
112
|
+
model = RevisionableTestModel.new(:name => 'test')
|
113
|
+
model.set_secret(1234)
|
114
|
+
model.save!
|
115
|
+
ActsAsRevisionable::RevisionRecord.count.should == 0
|
116
|
+
model.name = 'new_name'
|
117
|
+
model.save!
|
118
|
+
ActsAsRevisionable::RevisionRecord.count.should == 0
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should not save a revision if an update raises an exception" do
|
122
|
+
model = RevisionableTestModel.new(:name => 'test')
|
123
|
+
model.store_revision do
|
124
|
+
model.save!
|
125
|
+
end
|
126
|
+
model.reload
|
127
|
+
ActsAsRevisionable::RevisionRecord.count.should == 0
|
128
|
+
|
129
|
+
model.should_receive(:update).and_raise("update failed")
|
130
|
+
model.name = 'new_name'
|
131
|
+
begin
|
132
|
+
model.store_revision do
|
133
|
+
ActsAsRevisionable::RevisionRecord.count.should == 1
|
134
|
+
model.save
|
135
|
+
end
|
136
|
+
rescue
|
137
|
+
end
|
138
|
+
ActsAsRevisionable::RevisionRecord.count.should == 0
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should not save a revision if an update fails with errors" do
|
142
|
+
model = RevisionableTestModel.new(:name => 'test')
|
143
|
+
model.store_revision do
|
144
|
+
model.save!
|
145
|
+
end
|
146
|
+
model.reload
|
147
|
+
ActsAsRevisionable::RevisionRecord.count.should == 0
|
148
|
+
|
149
|
+
model.name = 'new_name'
|
150
|
+
model.store_revision do
|
151
|
+
ActsAsRevisionable::RevisionRecord.count.should == 1
|
152
|
+
model.save!
|
153
|
+
model.errors.add(:name, "isn't right")
|
154
|
+
end
|
155
|
+
ActsAsRevisionable::RevisionRecord.count.should == 0
|
156
|
+
end
|
157
|
+
|
158
|
+
it "should restore a record without associations" do
|
159
|
+
model = RevisionableTestModel.new(:name => 'test')
|
160
|
+
model.set_secret(1234)
|
161
|
+
model.store_revision do
|
162
|
+
model.save!
|
163
|
+
end
|
164
|
+
model.reload
|
165
|
+
ActsAsRevisionable::RevisionRecord.count.should == 0
|
166
|
+
|
167
|
+
model.name = 'new_name'
|
168
|
+
model.set_secret(5678)
|
169
|
+
model.store_revision do
|
170
|
+
model.save!
|
171
|
+
end
|
172
|
+
model.reload
|
173
|
+
ActsAsRevisionable::RevisionRecord.count.should == 1
|
174
|
+
model.name.should == 'new_name'
|
175
|
+
model.secret.should == 5678
|
176
|
+
|
177
|
+
restored = model.restore_revision(1)
|
178
|
+
restored.name.should == 'test'
|
179
|
+
restored.secret.should == 1234
|
180
|
+
restored.id.should == model.id
|
181
|
+
|
182
|
+
restored.store_revision do
|
183
|
+
restored.save!
|
184
|
+
end
|
185
|
+
RevisionableTestModel.count.should == 1
|
186
|
+
ActsAsRevisionable::RevisionRecord.count.should == 2
|
187
|
+
restored_model = RevisionableTestModel.find(model.id)
|
188
|
+
restored_model.name.should == restored.name
|
189
|
+
restored_model.secret.should == restored.secret
|
190
|
+
end
|
191
|
+
|
192
|
+
it "should restore a record with has_many associations" do
|
193
|
+
many_thing_1 = RevisionableTestManyThing.new(:name => 'many_thing_1')
|
194
|
+
many_thing_1.sub_things.build(:name => 'sub_thing_1')
|
195
|
+
many_thing_1.sub_things.build(:name => 'sub_thing_2')
|
196
|
+
|
197
|
+
model = RevisionableTestModel.new(:name => 'test')
|
198
|
+
model.many_things << many_thing_1
|
199
|
+
model.many_things.build(:name => 'many_thing_2')
|
200
|
+
model.many_other_things.build(:name => 'many_other_thing_1')
|
201
|
+
model.many_other_things.build(:name => 'many_other_thing_2')
|
202
|
+
model.save!
|
203
|
+
model.reload
|
204
|
+
RevisionableTestManyThing.count.should == 2
|
205
|
+
RevisionableTestSubThing.count.should == 2
|
206
|
+
RevisionableTestManyOtherThing.count.should == 2
|
207
|
+
ActsAsRevisionable::RevisionRecord.count.should == 0
|
208
|
+
|
209
|
+
model.store_revision do
|
210
|
+
model.name = 'new_name'
|
211
|
+
many_thing_1 = model.many_things.detect{|t| t.name == 'many_thing_1'}
|
212
|
+
many_thing_1.name = 'new_many_thing_1'
|
213
|
+
sub_thing_1 = many_thing_1.sub_things.detect{|t| t.name == 'sub_thing_1'}
|
214
|
+
sub_thing_1.name = 'new_sub_thing_1'
|
215
|
+
sub_thing_2 = many_thing_1.sub_things.detect{|t| t.name == 'sub_thing_2'}
|
216
|
+
many_thing_1.sub_things.build(:name => 'sub_thing_3')
|
217
|
+
many_thing_1.sub_things.delete(sub_thing_2)
|
218
|
+
many_thing_2 = model.many_things.detect{|t| t.name == 'many_thing_2'}
|
219
|
+
model.many_things.delete(many_thing_2)
|
220
|
+
model.many_things.build(:name => 'many_thing_3')
|
221
|
+
many_other_thing_1 = model.many_other_things.detect{|t| t.name == 'many_other_thing_1'}
|
222
|
+
many_other_thing_1.name = 'new_many_other_thing_1'
|
223
|
+
many_other_thing_2 = model.many_other_things.detect{|t| t.name == 'many_other_thing_2'}
|
224
|
+
model.many_other_things.delete(many_other_thing_2)
|
225
|
+
model.many_other_things.build(:name => 'many_other_thing_3')
|
226
|
+
model.save!
|
227
|
+
many_thing_1.save!
|
228
|
+
sub_thing_1.save!
|
229
|
+
many_other_thing_1.save!
|
230
|
+
end
|
231
|
+
|
232
|
+
model.reload
|
233
|
+
ActsAsRevisionable::RevisionRecord.count.should == 1
|
234
|
+
RevisionableTestManyThing.count.should == 2
|
235
|
+
RevisionableTestSubThing.count.should == 3
|
236
|
+
RevisionableTestManyOtherThing.count.should == 2
|
237
|
+
model.name.should == 'new_name'
|
238
|
+
model.many_things.collect{|t| t.name}.sort.should == ['many_thing_3', 'new_many_thing_1']
|
239
|
+
model.many_things.detect{|t| t.name == 'new_many_thing_1'}.sub_things.collect{|t| t.name}.sort.should == ['new_sub_thing_1', 'sub_thing_3']
|
240
|
+
model.many_other_things.collect{|t| t.name}.sort.should == ['many_other_thing_3', 'new_many_other_thing_1']
|
241
|
+
|
242
|
+
# restore to memory
|
243
|
+
restored = model.restore_revision(1)
|
244
|
+
restored.name.should == 'test'
|
245
|
+
restored.id.should == model.id
|
246
|
+
restored.many_things.collect{|t| t.name}.sort.should == ['many_thing_1', 'many_thing_2']
|
247
|
+
restored.many_things.detect{|t| t.name == 'many_thing_1'}.sub_things.collect{|t| t.name}.sort.should == ['sub_thing_1', 'sub_thing_2']
|
248
|
+
restored.many_other_things.collect{|t| t.name}.sort.should == ['many_other_thing_3', 'new_many_other_thing_1']
|
249
|
+
restored.valid?.should == true
|
250
|
+
|
251
|
+
# make the restore to memory didn't affect the database
|
252
|
+
model.reload
|
253
|
+
model.name.should == 'new_name'
|
254
|
+
model.many_things.collect{|t| t.name}.sort.should == ['many_thing_3', 'new_many_thing_1']
|
255
|
+
model.many_things.detect{|t| t.name == 'new_many_thing_1'}.sub_things.collect{|t| t.name}.sort.should == ['new_sub_thing_1', 'sub_thing_3']
|
256
|
+
model.many_other_things.collect{|t| t.name}.sort.should == ['many_other_thing_3', 'new_many_other_thing_1']
|
257
|
+
|
258
|
+
model.restore_revision!(1)
|
259
|
+
RevisionableTestModel.count.should == 1
|
260
|
+
RevisionableTestManyThing.count.should == 2
|
261
|
+
RevisionableTestSubThing.count.should == 3
|
262
|
+
RevisionableTestManyOtherThing.count.should == 2
|
263
|
+
ActsAsRevisionable::RevisionRecord.count.should == 2
|
264
|
+
restored_model = RevisionableTestModel.find(model.id)
|
265
|
+
restored_model.name.should == 'test'
|
266
|
+
restored.many_things.collect{|t| t.name}.sort.should == ['many_thing_1', 'many_thing_2']
|
267
|
+
restored.many_things.detect{|t| t.name == 'many_thing_1'}.sub_things.collect{|t| t.name}.sort.should == ['sub_thing_1', 'sub_thing_2']
|
268
|
+
restored.many_things.detect{|t| t.name == 'many_thing_2'}.sub_things.collect{|t| t.name}.sort.should == []
|
269
|
+
restored.many_other_things.collect{|t| t.name}.sort.should == ['many_other_thing_3', 'new_many_other_thing_1']
|
270
|
+
end
|
271
|
+
|
272
|
+
it "should restore a record with has_one associations" do
|
273
|
+
model = RevisionableTestModel.new(:name => 'test')
|
274
|
+
model.build_one_thing(:name => 'other')
|
275
|
+
model.store_revision do
|
276
|
+
model.save!
|
277
|
+
end
|
278
|
+
model.reload
|
279
|
+
ActsAsRevisionable::RevisionRecord.count.should == 0
|
280
|
+
RevisionableTestOneThing.count.should == 1
|
281
|
+
|
282
|
+
model.name = 'new_name'
|
283
|
+
model.one_thing.name = 'new_other'
|
284
|
+
model.store_revision do
|
285
|
+
model.one_thing.save!
|
286
|
+
model.save!
|
287
|
+
end
|
288
|
+
|
289
|
+
model.reload
|
290
|
+
ActsAsRevisionable::RevisionRecord.count.should == 1
|
291
|
+
model.name.should == 'new_name'
|
292
|
+
model.one_thing.name.should == 'new_other'
|
293
|
+
|
294
|
+
# restore to memory
|
295
|
+
restored = model.restore_revision(1)
|
296
|
+
restored.name.should == 'test'
|
297
|
+
restored.one_thing.name.should == 'other'
|
298
|
+
restored.one_thing.id.should == model.one_thing.id
|
299
|
+
|
300
|
+
# make sure restore to memory didn't affect the database
|
301
|
+
model.reload
|
302
|
+
ActsAsRevisionable::RevisionRecord.count.should == 1
|
303
|
+
model.name.should == 'new_name'
|
304
|
+
model.one_thing.name.should == 'new_other'
|
305
|
+
|
306
|
+
model.restore_revision!(1)
|
307
|
+
RevisionableTestModel.count.should == 1
|
308
|
+
RevisionableTestOneThing.count.should == 1
|
309
|
+
ActsAsRevisionable::RevisionRecord.count.should == 2
|
310
|
+
restored_model = RevisionableTestModel.find(model.id)
|
311
|
+
restored_model.name.should == 'test'
|
312
|
+
restored_model.one_thing.name.should == 'other'
|
313
|
+
restored_model.one_thing.id.should == model.one_thing.id
|
314
|
+
end
|
315
|
+
|
316
|
+
it "should restore a record with has_and_belongs_to_many associations" do
|
317
|
+
other_1 = NonRevisionableTestModel.create(:name => 'one')
|
318
|
+
other_2 = NonRevisionableTestModel.create(:name => 'two')
|
319
|
+
model = RevisionableTestModel.new(:name => 'test')
|
320
|
+
model.non_revisionable_test_models = [other_1, other_2]
|
321
|
+
model.store_revision do
|
322
|
+
model.save!
|
323
|
+
end
|
324
|
+
model.reload
|
325
|
+
ActsAsRevisionable::RevisionRecord.count.should == 0
|
326
|
+
NonRevisionableTestModel.count.should == 2
|
327
|
+
|
328
|
+
model.name = 'new_name'
|
329
|
+
other_1.name = '111'
|
330
|
+
other_3 = NonRevisionableTestModel.create(:name => '333')
|
331
|
+
model.store_revision do
|
332
|
+
model.non_revisionable_test_models = [other_1, other_3]
|
333
|
+
other_1.save!
|
334
|
+
model.save!
|
335
|
+
end
|
336
|
+
|
337
|
+
model.reload
|
338
|
+
ActsAsRevisionable::RevisionRecord.count.should == 1
|
339
|
+
NonRevisionableTestModel.count.should == 3
|
340
|
+
model.name.should == 'new_name'
|
341
|
+
model.non_revisionable_test_models.collect{|r| r.name}.sort.should == ['111', '333']
|
342
|
+
|
343
|
+
# restore to memory
|
344
|
+
restored = model.restore_revision(1)
|
345
|
+
restored.name.should == 'test'
|
346
|
+
restored.non_revisionable_test_models.collect{|r| r.name}.sort.should == ['111', 'two']
|
347
|
+
|
348
|
+
# make sure the restore to memory didn't affect the database
|
349
|
+
model.reload
|
350
|
+
model.name.should == 'new_name'
|
351
|
+
model.non_revisionable_test_models.collect{|r| r.name}.sort.should == ['111', '333']
|
352
|
+
|
353
|
+
model.restore_revision!(1)
|
354
|
+
NonRevisionableTestModelsRevisionableTestModel.count.should == 2
|
355
|
+
RevisionableTestModel.count.should == 1
|
356
|
+
NonRevisionableTestModel.count.should == 3
|
357
|
+
ActsAsRevisionable::RevisionRecord.count.should == 2
|
358
|
+
restored_model = RevisionableTestModel.find(model.id)
|
359
|
+
restored_model.name.should == 'test'
|
360
|
+
restored_model.non_revisionable_test_models.collect{|r| r.name}.sort.should == ['111', 'two']
|
361
|
+
end
|
362
|
+
|
363
|
+
it "should handle namespaces and single table inheritance" do
|
364
|
+
model = ActsAsRevisionable::RevisionableNamespaceModel.new(:name => 'test')
|
365
|
+
model.store_revision do
|
366
|
+
model.save!
|
367
|
+
end
|
368
|
+
model.reload
|
369
|
+
ActsAsRevisionable::RevisionRecord.count.should == 0
|
370
|
+
|
371
|
+
model.name = 'new_name'
|
372
|
+
model.store_revision do
|
373
|
+
model.save!
|
374
|
+
end
|
375
|
+
model.reload
|
376
|
+
ActsAsRevisionable::RevisionRecord.count.should == 1
|
377
|
+
model.name.should == 'new_name'
|
378
|
+
|
379
|
+
restored = model.restore_revision(1)
|
380
|
+
restored.class.should == ActsAsRevisionable::RevisionableNamespaceModel
|
381
|
+
restored.name.should == 'test'
|
382
|
+
restored.id.should == model.id
|
383
|
+
end
|
384
|
+
|
385
|
+
it "should handle single table inheritance" do
|
386
|
+
model = ActsAsRevisionable::RevisionableSubclassModel.new(:name => 'test')
|
387
|
+
model.store_revision do
|
388
|
+
model.save!
|
389
|
+
end
|
390
|
+
model.reload
|
391
|
+
ActsAsRevisionable::RevisionRecord.count.should == 0
|
392
|
+
|
393
|
+
model.name = 'new_name'
|
394
|
+
model.store_revision do
|
395
|
+
model.save!
|
396
|
+
end
|
397
|
+
model.reload
|
398
|
+
ActsAsRevisionable::RevisionRecord.count.should == 1
|
399
|
+
model.name.should == 'new_name'
|
400
|
+
|
401
|
+
restored = model.restore_revision(1)
|
402
|
+
restored.class.should == ActsAsRevisionable::RevisionableSubclassModel
|
403
|
+
restored.name.should == 'test'
|
404
|
+
restored.id.should == model.id
|
405
|
+
restored.type_name.should == 'ActsAsRevisionable::RevisionableSubclassModel'
|
406
|
+
end
|
407
|
+
|
408
|
+
it "should destroy revisions if :dependent => :keep was not specified" do
|
409
|
+
model = RevisionableTestModel.new(:name => 'test')
|
410
|
+
model.store_revision do
|
411
|
+
model.save!
|
412
|
+
end
|
413
|
+
model.reload
|
414
|
+
ActsAsRevisionable::RevisionRecord.count.should == 0
|
415
|
+
|
416
|
+
model.name = 'new_name'
|
417
|
+
model.store_revision do
|
418
|
+
model.save!
|
419
|
+
end
|
420
|
+
model.reload
|
421
|
+
ActsAsRevisionable::RevisionRecord.count.should == 1
|
422
|
+
model.name.should == 'new_name'
|
423
|
+
|
424
|
+
model.destroy
|
425
|
+
ActsAsRevisionable::RevisionRecord.count.should == 0
|
426
|
+
end
|
427
|
+
|
428
|
+
it "should not destroy revisions if :dependent => :keep was specified" do
|
429
|
+
model = ActsAsRevisionable::RevisionableSubclassModel.new(:name => 'test')
|
430
|
+
model.store_revision do
|
431
|
+
model.save!
|
432
|
+
end
|
433
|
+
model.reload
|
434
|
+
ActsAsRevisionable::RevisionRecord.count.should == 0
|
435
|
+
|
436
|
+
model.name = 'new_name'
|
437
|
+
model.store_revision do
|
438
|
+
model.save!
|
439
|
+
end
|
440
|
+
model.reload
|
441
|
+
ActsAsRevisionable::RevisionRecord.count.should == 1
|
442
|
+
model.name.should == 'new_name'
|
443
|
+
|
444
|
+
model.destroy
|
445
|
+
ActsAsRevisionable::RevisionRecord.count.should == 1
|
446
|
+
end
|
447
|
+
|
448
|
+
end
|