acts_as_revisionable 1.0.6 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,213 +1,234 @@
1
- require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
1
+ require 'spec_helper'
2
2
  require 'zlib'
3
3
 
4
4
  describe ActsAsRevisionable::RevisionRecord do
5
-
5
+
6
6
  before :all do
7
7
  ActsAsRevisionable::Test.create_database
8
- end
9
-
10
- after :all do
11
- ActsAsRevisionable::Test.delete_database
12
- end
13
-
14
- class TestRevisionableRecord
15
- attr_accessor :attributes
16
-
17
- def self.base_class
18
- self
8
+ ActsAsRevisionable::RevisionRecord.create_table
9
+
10
+ class TestRevisionableAssociationLegacyRecord < ActiveRecord::Base
11
+ connection.create_table(table_name, :id => false) do |t|
12
+ t.column :legacy_id, :integer
13
+ t.column :name, :string
14
+ t.column :value, :integer
15
+ t.column :test_revisionable_record_id, :integer
16
+ end unless table_exists?
17
+ self.primary_key = :legacy_id
19
18
  end
20
19
 
21
- def self.inheritance_column
22
- 'type'
23
- end
24
-
25
- def self.store_full_sti_class
26
- true
27
- end
28
-
29
- def initialize (attributes = {})
30
- @attributes = attributes
31
- end
32
-
33
- def self.reflections
34
- @reflections || {}
35
- end
36
-
37
- def self.reflections= (vals)
38
- @reflections = vals
39
- end
40
-
41
- def id
42
- attributes['id']
20
+ class TestRevisionableOneAssociationRecord < ActiveRecord::Base
21
+ connection.create_table(table_name, :id => false) do |t|
22
+ t.column :name, :string
23
+ t.column :value, :integer
24
+ t.column :test_revisionable_record_id, :integer
25
+ end unless table_exists?
43
26
  end
44
27
 
45
- def id= (val)
46
- attributes['id'] = val
28
+ class TestRevisionableAssociationComposite < ActiveRecord::Base
29
+ connection.create_table(table_name, :id => false) do |t|
30
+ t.column :first_id, :integer
31
+ t.column :second_id, :integer
32
+ t.column :name, :string
33
+ t.column :value, :integer
34
+ end unless table_exists?
35
+ set_primary_keys :first_id, :second_id
47
36
  end
48
-
49
- def name= (val)
50
- attributes['name'] = val
37
+
38
+ class TestRevisionableAssociationRecord < ActiveRecord::Base
39
+ connection.create_table(table_name) do |t|
40
+ t.column :name, :string
41
+ t.column :value, :integer
42
+ t.column :test_revisionable_record_id, :integer
43
+ end unless table_exists?
44
+
45
+ has_one :sub_association, :class_name => 'TestRevisionableSubAssociationRecord'
51
46
  end
52
-
53
- def value= (val)
54
- attributes['value'] = val
47
+
48
+ class OtherRevisionableRecordsTestRevisionableRecords < ActiveRecord::Base
49
+ connection.create_table(table_name, :id => false) do |t|
50
+ t.column :test_revisionable_record_id, :integer
51
+ t.column :other_revisionable_record_id, :integer
52
+ end unless table_exists?
55
53
  end
56
-
57
- def self.revisionable_associations
58
- nil
54
+
55
+ class TestRevisionableSubAssociationRecord < ActiveRecord::Base
56
+ connection.create_table(table_name) do |t|
57
+ t.column :name, :string
58
+ t.column :value, :integer
59
+ t.column :test_revisionable_association_record_id, :integer
60
+ end unless table_exists?
59
61
  end
60
-
61
- def self.type_name_with_module (type_name)
62
- type_name
62
+
63
+ module ActsAsRevisionable
64
+ class TestModuleRecord < ActiveRecord::Base
65
+ connection.create_table(table_name) do |t|
66
+ t.column :name, :string
67
+ t.column :value, :integer
68
+ end unless table_exists?
69
+ end
63
70
  end
64
- end
65
-
66
- class TestRevisionableAssociationRecord < TestRevisionableRecord
67
- def self.reflections
68
- @reflections || {}
71
+
72
+ class TestRevisionableRecord < ActiveRecord::Base
73
+ connection.create_table(table_name) do |t|
74
+ t.column :name, :string
75
+ t.column :value, :integer
76
+ t.column :test_revisionable_one_association_record_id, :integer
77
+ end unless table_exists?
78
+
79
+ has_many :associations, :class_name => 'TestRevisionableAssociationRecord'
80
+ has_many :legacy_associations, :class_name => 'TestRevisionableAssociationLegacyRecord'
81
+ has_many :composit_associations, :class_name => 'TestRevisionableAssociationComposite', :foreign_key => :first_id
82
+ has_and_belongs_to_many :other_revisionable_records
83
+ has_one :one_association, :class_name => 'TestRevisionableOneAssociationRecord'
84
+
85
+ acts_as_revisionable :associations => [{:associations => :sub_association}, :one_association, :other_revisionable_records]
69
86
  end
70
87
 
71
- def self.reflections= (vals)
72
- @reflections = vals
73
- end
74
- end
75
-
76
- class TestRevisionableSubAssociationRecord < TestRevisionableRecord
77
- def self.reflections
78
- @reflections || {}
88
+ class OtherRevisionableRecord < ActiveRecord::Base
89
+ connection.create_table(table_name) do |t|
90
+ t.column :name, :string
91
+ t.column :value, :integer
92
+ t.column :type, :string
93
+ end unless table_exists?
79
94
  end
80
95
 
81
- def self.reflections= (vals)
82
- @reflections = vals
96
+ class TestInheritanceRecord < OtherRevisionableRecord
97
+ def self.base_class
98
+ OtherRevisionableRecord
99
+ end
83
100
  end
84
101
  end
85
-
86
- module ActsAsRevisionable
87
- class TestModuleRecord < TestRevisionableRecord
88
- end
89
- end
90
-
91
- class TestInheritanceRecord < TestRevisionableRecord
92
- def self.base_class
93
- TestRevisionableRecord
94
- end
95
-
96
- def initialize (attributes = {})
97
- super({'type' => 'TestInheritanceRecord'}.merge(attributes))
98
- end
99
-
100
- def type= (val)
101
- attributes['type'] = val
102
- end
102
+
103
+ after :all do
104
+ ActsAsRevisionable::Test.delete_database
103
105
  end
104
-
105
- before(:each) do
106
- TestRevisionableRecord.reflections = nil
107
- TestRevisionableAssociationRecord.reflections = nil
108
- TestRevisionableSubAssociationRecord.reflections = nil
106
+
107
+ before :each do
108
+ ActsAsRevisionable::RevisionRecord.delete_all
109
+ TestRevisionableRecord.delete_all
110
+ TestRevisionableAssociationLegacyRecord.delete_all
111
+ TestRevisionableAssociationRecord.delete_all
112
+ TestRevisionableSubAssociationRecord.delete_all
113
+ ActsAsRevisionable::TestModuleRecord.delete_all
114
+ OtherRevisionableRecord.delete_all
115
+ TestInheritanceRecord.delete_all
116
+ OtherRevisionableRecordsTestRevisionableRecords.delete_all
117
+ TestRevisionableOneAssociationRecord.delete_all
109
118
  end
110
-
119
+
111
120
  it "should set the revision number before it creates the record" do
112
- ActsAsRevisionable::RevisionRecord.delete_all
113
- revision1 = ActsAsRevisionable::RevisionRecord.new(TestRevisionableRecord.new('id' => 1))
121
+ record = TestRevisionableRecord.create(:name => "test")
122
+ revision1 = ActsAsRevisionable::RevisionRecord.new(record)
114
123
  revision1.save!
115
- revision2 = ActsAsRevisionable::RevisionRecord.new(TestRevisionableRecord.new('id' => 1))
124
+ revision2 = ActsAsRevisionable::RevisionRecord.new(record)
116
125
  revision2.save!
117
126
  revision1.revision.should == 1
118
127
  revision2.revision.should == 2
119
128
  revision2.revision = 20
120
129
  revision2.save!
121
- revision3 = ActsAsRevisionable::RevisionRecord.new(TestRevisionableRecord.new('id' => 1))
130
+ revision3 = ActsAsRevisionable::RevisionRecord.new(record)
122
131
  revision3.save!
123
132
  revision3.revision.should == 21
124
- ActsAsRevisionable::RevisionRecord.delete_all
125
133
  end
126
-
134
+
127
135
  it "should serialize all the attributes of the original model" do
128
- attributes = {'id' => 1, 'name' => 'revision', 'value' => 5}
129
- original = TestRevisionableRecord.new(attributes)
136
+ original = TestRevisionableRecord.new('name' => 'revision', 'value' => 5)
137
+ original.id = 1
130
138
  revision = ActsAsRevisionable::RevisionRecord.new(original)
131
139
  revision.revisionable_id.should == 1
132
140
  revision.revisionable_type.should == "TestRevisionableRecord"
133
- revision.revision_attributes.should == attributes
141
+ revision.revision_attributes['name'].should == 'revision'
142
+ revision.revision_attributes['value'].should == 5
134
143
  end
135
-
144
+
136
145
  it "should serialize all the attributes of revisionable has_many associations" do
137
- attributes = {'id' => 1, 'name' => 'revision', 'value' => Time.now}
138
- association_attributes_1 = {'id' => 2, 'name' => 'association_1'}
139
- association_attributes_2 = {'id' => 3, 'name' => 'association_2'}
140
- original = TestRevisionableRecord.new(attributes)
141
- revisionable_associations = [TestRevisionableAssociationRecord.new(association_attributes_1), TestRevisionableAssociationRecord.new(association_attributes_2)]
142
- revisionable_associations_reflection = stub(:association, :name => :revisionable_associations, :macro => :has_many, :options => {:dependent => :destroy})
143
- non_revisionable_associations_reflection = stub(:association, :name => :non_revisionable_associations, :macro => :has_many, :options => {})
144
-
145
- TestRevisionableRecord.should_receive(:revisionable_associations).and_return(:revisionable_associations => true)
146
- TestRevisionableRecord.reflections = {:revisionable_associations => revisionable_associations_reflection, :non_revisionable_associations => non_revisionable_associations_reflection}
147
- original.should_not_receive(:non_revisionable_associations)
148
- original.should_receive(:revisionable_associations).and_return(revisionable_associations)
149
-
146
+ original = TestRevisionableRecord.new(:name => 'revision', :value => 1)
147
+ association_1 = original.associations.build(:name => 'association 1', :value => 2)
148
+ association_2 = original.associations.build(:name => 'association 2', :value => 3)
149
+ original.save!
150
150
  revision = ActsAsRevisionable::RevisionRecord.new(original)
151
- revision.revision_attributes.should == attributes.merge('revisionable_associations' => [association_attributes_1, association_attributes_2])
151
+ revision.revision_attributes['associations'].should == [
152
+ {
153
+ "id" => association_1.id,
154
+ "name" => "association 1",
155
+ "value" => 2,
156
+ "test_revisionable_record_id" => original.id,
157
+ "sub_association" => nil
158
+ },
159
+ {
160
+ "id" => association_2.id,
161
+ "name" => "association 2",
162
+ "value" => 3,
163
+ "test_revisionable_record_id" => original.id,
164
+ "sub_association" => nil
165
+ }
166
+ ]
152
167
  end
153
-
168
+
154
169
  it "should serialize all the attributes of revisionable has_one associations" do
155
- attributes = {'id' => 1, 'name' => 'revision', 'value' => Date.today}
156
- association_attributes = {'id' => 2, 'name' => 'association_1'}
157
- original = TestRevisionableRecord.new(attributes)
158
- revisionable_association = TestRevisionableAssociationRecord.new(association_attributes)
159
- revisionable_association_reflection = stub(:association, :name => :revisionable_association, :macro => :has_one, :options => {:dependent => :destroy})
160
- non_revisionable_association_reflection = stub(:association, :name => :non_revisionable_association, :macro => :has_one, :options => {})
161
-
162
- TestRevisionableRecord.should_receive(:revisionable_associations).and_return(:revisionable_association => true)
163
- TestRevisionableRecord.reflections = {:revisionable_association => revisionable_association_reflection, :non_revisionable_association => non_revisionable_association_reflection}
164
- original.should_not_receive(:non_revisionable_association)
165
- original.should_receive(:revisionable_association).and_return(revisionable_association)
166
-
170
+ original = TestRevisionableRecord.new(:name => 'revision', :value => 1)
171
+ one = original.build_one_association(:name => 'one', :value => 2)
172
+ original.save!
167
173
  revision = ActsAsRevisionable::RevisionRecord.new(original)
168
- revision.revision_attributes.should == attributes.merge('revisionable_association' => association_attributes)
174
+ revision.revision_attributes['one_association'].should == {
175
+ "id"=>one.id, "name"=>"one", "value"=>2, "test_revisionable_record_id"=>original.id
176
+ }
169
177
  end
170
-
178
+
171
179
  it "should serialize all revisionable has_many_and_belongs_to_many associations" do
172
- attributes = {'id' => 1, 'name' => 'revision'}
173
- original = TestRevisionableRecord.new(attributes)
174
- revisionable_associations_reflection = stub(:association, :name => :revisionable_associations, :macro => :has_and_belongs_to_many, :options => {:dependent => :destroy})
175
- non_revisionable_associations_reflection = stub(:association, :name => :non_revisionable_associations, :macro => :has_and_belongs_to_many, :options => {})
176
-
177
- TestRevisionableRecord.should_receive(:revisionable_associations).and_return(:revisionable_associations => true)
178
- TestRevisionableRecord.reflections = {:revisionable_associations => revisionable_associations_reflection, :non_revisionable_associations => non_revisionable_associations_reflection}
179
- original.should_receive(:revisionable_association_ids).and_return([2, 3, 4])
180
-
180
+ original = TestRevisionableRecord.new(:name => 'revision', :value => 1)
181
+ other_1 = OtherRevisionableRecord.create(:name => "other 1")
182
+ other_2 = OtherRevisionableRecord.create(:name => "other 2")
183
+ other_3 = OtherRevisionableRecord.create(:name => "other 3")
184
+ original.other_revisionable_records << other_1
185
+ original.other_revisionable_records << other_2
186
+ original.other_revisionable_records << other_3
187
+ original.save!
181
188
  revision = ActsAsRevisionable::RevisionRecord.new(original)
182
- revision.revision_attributes.should == attributes.merge('revisionable_associations' => [2, 3, 4])
189
+ revision.revision_attributes['other_revisionable_records'].sort.should == [other_1.id, other_2.id, other_3.id]
183
190
  end
184
-
185
- it "should serialize revisionable associations of revisionable associations with :dependent => :destroy" do
186
- attributes = {'id' => 1, 'name' => 'revision', 'value' => Time.now}
187
- association_attributes_1 = {'id' => 2, 'name' => 'association_1'}
188
- association_attributes_2 = {'id' => 3, 'name' => 'association_2'}
189
- original = TestRevisionableRecord.new(attributes)
190
- association_1 = TestRevisionableAssociationRecord.new(association_attributes_1)
191
- association_2 = TestRevisionableAssociationRecord.new(association_attributes_2)
192
- revisionable_associations = [association_1, association_2]
193
- revisionable_associations_reflection = stub(:association, :name => :revisionable_associations, :macro => :has_many, :options => {:dependent => :destroy})
194
- sub_association_attributes = {'id' => 4, 'name' => 'sub_association_1'}
195
- sub_association = TestRevisionableSubAssociationRecord.new(sub_association_attributes)
196
- sub_association_reflection = stub(:sub_association, :name => :sub_association, :macro => :has_one, :options => {:dependent => :destroy})
197
-
198
- TestRevisionableRecord.should_receive(:revisionable_associations).and_return(:revisionable_associations => {:sub_association => true})
199
- TestRevisionableRecord.reflections = {:revisionable_associations => revisionable_associations_reflection}
200
- TestRevisionableAssociationRecord.reflections = {:sub_association => sub_association_reflection}
201
- original.should_receive(:revisionable_associations).and_return(revisionable_associations)
202
- association_1.should_receive(:sub_association).and_return(sub_association)
203
- association_2.should_receive(:sub_association).and_return(nil)
204
-
191
+
192
+ it "should serialize revisionable associations of revisionable associations" do
193
+ original = TestRevisionableRecord.new(:name => 'revision', :value => 1)
194
+ association_1 = original.associations.build(:name => 'association 1', :value => 2)
195
+ association_2 = original.associations.build(:name => 'association 2', :value => 3)
196
+ sub_association = association_1.build_sub_association(:name => 'sub', :value => 4)
197
+ original.save!
205
198
  revision = ActsAsRevisionable::RevisionRecord.new(original)
206
- revision.revision_attributes.should == attributes.merge('revisionable_associations' => [association_attributes_1.merge('sub_association' => sub_association_attributes), association_attributes_2.merge('sub_association' => nil)])
199
+ revision.revision_attributes.should == {
200
+ "id" => original.id,
201
+ "name" => "revision",
202
+ "value" => 1,
203
+ "associations" => [
204
+ {
205
+ "id" => association_1.id,
206
+ "name" => "association 1",
207
+ "value" => 2,
208
+ "test_revisionable_record_id" => original.id,
209
+ "sub_association" => {
210
+ "id" => sub_association.id,
211
+ "name" => "sub",
212
+ "value" => 4,
213
+ "test_revisionable_association_record_id" => association_1.id
214
+ }
215
+ },
216
+ {
217
+ "id" => association_2.id,
218
+ "name" => "association 2",
219
+ "value" => 3,
220
+ "test_revisionable_record_id" => original.id,
221
+ "sub_association" => nil
222
+ }
223
+ ],
224
+ "test_revisionable_one_association_record_id" => nil,
225
+ "other_revisionable_records" => [],
226
+ "one_association" => nil
227
+ }
207
228
  end
208
-
229
+
209
230
  it "should be able to restore the original model using Ruby serialization" do
210
- attributes = {'id' => 1, 'name' => 'revision', 'value' => 5}
231
+ attributes = {'id' => 1, 'name' => 'revision', 'value' => 5, 'test_revisionable_one_association_record_id' => nil}
211
232
  revision = ActsAsRevisionable::RevisionRecord.new(TestRevisionableRecord.new(attributes), :ruby)
212
233
  revision.data = Zlib::Deflate.deflate(Marshal.dump(attributes))
213
234
  restored = revision.restore
@@ -215,9 +236,9 @@ describe ActsAsRevisionable::RevisionRecord do
215
236
  restored.id.should == 1
216
237
  restored.attributes.should == attributes
217
238
  end
218
-
239
+
219
240
  it "should be able to restore the original model using YAML serialization" do
220
- attributes = {'id' => 1, 'name' => 'revision', 'value' => 5}
241
+ attributes = {'id' => 1, 'name' => 'revision', 'value' => 5, 'test_revisionable_one_association_record_id' => nil}
221
242
  revision = ActsAsRevisionable::RevisionRecord.new(TestRevisionableRecord.new(attributes), :yaml)
222
243
  revision.data = Zlib::Deflate.deflate(YAML.dump(attributes))
223
244
  restored = revision.restore
@@ -225,9 +246,9 @@ describe ActsAsRevisionable::RevisionRecord do
225
246
  restored.id.should == 1
226
247
  restored.attributes.should == attributes
227
248
  end
228
-
249
+
229
250
  it "should be able to restore the original model using XML serialization" do
230
- attributes = {'id' => 1, 'name' => 'revision', 'value' => 5}
251
+ attributes = {'id' => 1, 'name' => 'revision', 'value' => 5, 'test_revisionable_one_association_record_id' => nil}
231
252
  revision = ActsAsRevisionable::RevisionRecord.new(TestRevisionableRecord.new(attributes), :xml)
232
253
  revision.data = Zlib::Deflate.deflate(YAML.dump(attributes))
233
254
  restored = revision.restore
@@ -235,113 +256,105 @@ describe ActsAsRevisionable::RevisionRecord do
235
256
  restored.id.should == 1
236
257
  restored.attributes.should == attributes
237
258
  end
238
-
259
+
239
260
  it "should be able to restore associations" do
240
261
  restored = TestRevisionableRecord.new
241
262
  attributes = {'id' => 1, 'name' => 'revision', 'value' => Time.now, :associations => {'id' => 2, 'value' => 'val'}}
242
263
  revision = ActsAsRevisionable::RevisionRecord.new(TestRevisionableRecord.new)
243
264
  revision.data = Zlib::Deflate.deflate(Marshal.dump(attributes))
244
- associations_reflection = stub(:associations, :name => :associations, :macro => :has_many, :options => {:dependent => :destroy})
245
- TestRevisionableRecord.reflections = {:associations => associations_reflection}
246
265
  TestRevisionableRecord.should_receive(:new).and_return(restored)
247
266
  revision.should_receive(:restore_association).with(restored, :associations, {'id' => 2, 'value' => 'val'})
248
267
  restored = revision.restore
249
268
  end
250
-
269
+
251
270
  it "should be able to restore the has_many associations" do
252
271
  revision = ActsAsRevisionable::RevisionRecord.new(TestRevisionableRecord.new)
253
272
  record = TestRevisionableRecord.new
254
-
255
- associations_reflection = stub(:associations, :name => :associations, :macro => :has_many, :options => {:dependent => :destroy})
256
- TestRevisionableRecord.reflections = {:associations => associations_reflection}
257
- associations = mock(:associations)
258
- record.should_receive(:associations).and_return(associations)
259
- associated_record = TestRevisionableAssociationRecord.new
260
- associations.should_receive(:build).and_return(associated_record)
261
-
262
- revision.send(:restore_association, record, :associations, {'id' => 1, 'value' => 'val'})
273
+ revision.send(:restore_association, record, :associations, {'id' => 1, 'name' => 'assoc', 'value' => 10})
274
+ record.associations.size.should == 1
275
+ associated_record = record.associations.first
263
276
  associated_record.id.should == 1
264
- associated_record.attributes.should == {'id' => 1, 'value' => 'val'}
277
+ associated_record.name.should == 'assoc'
278
+ associated_record.value.should == 10
265
279
  end
266
-
267
- it "should be able to restore the has_one associations" do
280
+
281
+ it "should be able to restore the has_many associations with a legacy primary key" do
268
282
  revision = ActsAsRevisionable::RevisionRecord.new(TestRevisionableRecord.new)
269
283
  record = TestRevisionableRecord.new
270
-
271
- association_reflection = stub(:associations, :name => :association, :macro => :has_one, :klass => TestRevisionableAssociationRecord, :options => {:dependent => :destroy})
272
- TestRevisionableRecord.reflections = {:association => association_reflection}
273
- associated_record = TestRevisionableAssociationRecord.new
274
- TestRevisionableAssociationRecord.should_receive(:new).and_return(associated_record)
275
- record.should_receive(:association=).with(associated_record)
276
-
277
- revision.send(:restore_association, record, :association, {'id' => 1, 'value' => 'val'})
284
+ revision.send(:restore_association, record, :legacy_associations, {'legacy_id' => 1, 'name' => 'legacy', 'value' => 10})
285
+ record.legacy_associations.size.should == 1
286
+ associated_record = record.legacy_associations.first
278
287
  associated_record.id.should == 1
279
- associated_record.attributes.should == {'id' => 1, 'value' => 'val'}
288
+ associated_record.name.should == 'legacy'
289
+ associated_record.value.should == 10
280
290
  end
281
-
291
+
292
+ it "should be able to restore the has_many associations with composite primary keys" do
293
+ revision = ActsAsRevisionable::RevisionRecord.new(TestRevisionableRecord.new)
294
+ record = TestRevisionableRecord.new
295
+ revision.send(:restore_association, record, :composit_associations, {'first_id' => 1, 'second_id' => 2, 'name' => 'composit', 'value' => 10})
296
+ record.composit_associations.size.should == 1
297
+ associated_record = record.composit_associations.first
298
+ associated_record.first_id.should == 1
299
+ associated_record.second_id.should == 2
300
+ associated_record.name.should == 'composit'
301
+ associated_record.value.should == 10
302
+ end
303
+
304
+ it "should be able to restore the has_one associations" do
305
+ revision = ActsAsRevisionable::RevisionRecord.new(TestRevisionableRecord.new)
306
+ record = TestRevisionableRecord.new
307
+ revision.send(:restore_association, record, :one_association, {'id' => 1, 'name' => 'one', 'value' => 1})
308
+ record.one_association.id.should == 1
309
+ record.one_association.name.should == 'one'
310
+ record.one_association.value.should == 1
311
+ end
312
+
282
313
  it "should be able to restore the has_and_belongs_to_many associations" do
314
+ other_1 = OtherRevisionableRecord.create(:name => "other 1")
315
+ other_2 = OtherRevisionableRecord.create(:name => "other 2")
316
+ other_3 = OtherRevisionableRecord.create(:name => "other 3")
283
317
  revision = ActsAsRevisionable::RevisionRecord.new(TestRevisionableRecord.new)
284
318
  record = TestRevisionableRecord.new
285
-
286
- associations_reflection = stub(:associations, :name => :associations, :macro => :has_and_belongs_to_many, :options => {})
287
- TestRevisionableRecord.reflections = {:associations => associations_reflection}
288
- record.should_receive(:association_ids=).with([2, 3, 4])
289
-
290
- revision.send(:restore_association, record, :associations, [2, 3, 4])
319
+ revision.send(:restore_association, record, :other_revisionable_records, [other_1.id, other_2.id, other_3.id])
320
+ record.other_revisionable_records.collect{|r| r.id}.sort.should == [other_1.id, other_2.id, other_3.id]
291
321
  end
292
-
322
+
293
323
  it "should be able to restore associations of associations" do
294
324
  revision = ActsAsRevisionable::RevisionRecord.new(TestRevisionableRecord.new)
295
325
  record = TestRevisionableRecord.new
296
-
297
- associations_reflection = stub(:associations, :name => :associations, :macro => :has_many, :options => {:dependent => :destroy})
298
- TestRevisionableRecord.reflections = {:associations => associations_reflection}
299
- associations = mock(:associations)
300
- record.should_receive(:associations).and_return(associations)
301
- associated_record = TestRevisionableAssociationRecord.new
302
- associations.should_receive(:build).and_return(associated_record)
303
-
304
- sub_associated_record = TestRevisionableSubAssociationRecord.new
305
- TestRevisionableAssociationRecord.should_receive(:new).and_return(sub_associated_record)
306
- sub_association_reflection = stub(:sub_association, :name => :sub_association, :macro => :has_one, :klass => TestRevisionableAssociationRecord, :options => {:dependent => :destroy})
307
- TestRevisionableAssociationRecord.reflections = {:sub_association => sub_association_reflection}
308
- associated_record.should_receive(:sub_association=).with(sub_associated_record)
309
-
310
- revision.send(:restore_association, record, :associations, {'id' => 1, 'value' => 'val', :sub_association => {'id' => 2, 'value' => 'sub'}})
326
+ revision.send(:restore_association, record, :associations, {'id' => 1, 'name' => 'assoc', 'value' => 10, :sub_association => {'id' => 2, 'name' => 'sub', 'value' => 1000}})
327
+ record.associations.size.should == 1
328
+ associated_record = record.associations.first
311
329
  associated_record.id.should == 1
312
- associated_record.attributes.should == {'id' => 1, 'value' => 'val'}
330
+ associated_record.name.should == 'assoc'
331
+ associated_record.value.should == 10
332
+ sub_associated_record = associated_record.sub_association
313
333
  sub_associated_record.id.should == 2
314
- sub_associated_record.attributes.should == {'id' => 2, 'value' => 'sub'}
334
+ sub_associated_record.name.should == 'sub'
335
+ sub_associated_record.value.should == 1000
315
336
  end
316
-
337
+
317
338
  it "should be able to restore a record for a model that has changed and add errors to the restored record" do
318
339
  restored = TestRevisionableRecord.new
319
340
  attributes = {'id' => 1, 'name' => 'revision', 'value' => Time.now, 'deleted_attribute' => 'abc', :bad_association => {'id' => 3, 'value' => :val}, :associations => {'id' => 2, 'value' => 'val', 'other' => 'val2'}}
320
341
  revision = ActsAsRevisionable::RevisionRecord.new(TestRevisionableRecord.new)
321
342
  revision.data = Zlib::Deflate.deflate(Marshal.dump(attributes))
322
343
  TestRevisionableRecord.should_receive(:new).and_return(restored)
323
-
344
+
324
345
  associations = mock(:associations)
325
346
  restored.should_receive(:associations).and_return(associations)
326
347
  associated_record = TestRevisionableAssociationRecord.new
327
348
  associations.should_receive(:build).and_return(associated_record)
328
-
329
- mock_record_errors = {}
330
- restored.stub!(:errors).and_return(mock_record_errors)
331
- mock_record_errors.should_receive(:add).with(:bad_association, "could not be restored to {\"id\"=>3, \"value\"=>:val}")
332
- mock_record_errors.should_receive(:add).with(:deleted_attribute, 'could not be restored to "abc"')
333
- mock_record_errors.should_receive(:add).with(:associations, 'could not be restored from the revision')
334
-
335
- mock_association_errors = mock(:errors)
336
- associated_record.stub!(:errors).and_return(mock_association_errors)
337
- mock_association_errors.should_receive(:add).with(:other, 'could not be restored to "val2"')
338
-
339
- associations_reflection = stub(:associations, :name => :associations, :macro => :has_many, :options => {:dependent => :destroy})
340
- TestRevisionableRecord.reflections = {:associations => associations_reflection}
341
-
349
+
342
350
  restored = revision.restore
351
+
352
+ restored.errors[:deleted_attribute].should include("could not be restored to \"abc\"")
353
+ restored.errors[:bad_association].should include("could not be restored to {\"id\"=>3, \"value\"=>:val}")
354
+ restored.errors[:associations].should include("could not be restored from the revision")
355
+ associated_record.errors[:other].should include("could not be restored to \"val2\"")
343
356
  end
344
-
357
+
345
358
  it "should be able to truncate the revisions for a record" do
346
359
  revision = ActsAsRevisionable::RevisionRecord.new(TestRevisionableRecord.new(:name => 'name'))
347
360
  revision.revision = 20
@@ -349,7 +362,7 @@ describe ActsAsRevisionable::RevisionRecord do
349
362
  ActsAsRevisionable::RevisionRecord.should_receive(:delete_all).with(['revisionable_type = ? AND revisionable_id = ? AND revision <= ?', 'TestRevisionableRecord', 1, 20])
350
363
  ActsAsRevisionable::RevisionRecord.truncate_revisions(TestRevisionableRecord, 1, :limit => 15)
351
364
  end
352
-
365
+
353
366
  it "should be able to truncate the revisions for a record by age" do
354
367
  revision = ActsAsRevisionable::RevisionRecord.new(TestRevisionableRecord.new(:name => 'name'))
355
368
  revision.revision = 20
@@ -360,25 +373,31 @@ describe ActsAsRevisionable::RevisionRecord do
360
373
  ActsAsRevisionable::RevisionRecord.should_receive(:delete_all).with(['revisionable_type = ? AND revisionable_id = ? AND revision <= ?', 'TestRevisionableRecord', 1, 20])
361
374
  ActsAsRevisionable::RevisionRecord.truncate_revisions(TestRevisionableRecord, 1, :minimum_age => minimum_age)
362
375
  end
363
-
376
+
364
377
  it "should not truncate the revisions for a record if it doesn't have enough" do
365
378
  ActsAsRevisionable::RevisionRecord.should_receive(:find).with(:first, :conditions => ['revisionable_type = ? AND revisionable_id = ?', 'TestRevisionableRecord', 1], :offset => 15, :order => 'revision DESC').and_return(nil)
366
379
  ActsAsRevisionable::RevisionRecord.should_not_receive(:delete_all)
367
380
  ActsAsRevisionable::RevisionRecord.truncate_revisions(TestRevisionableRecord, 1, :limit => 15)
368
381
  end
369
-
382
+
370
383
  it "should not truncate the revisions for a record if no limit or minimum_age is set" do
371
384
  ActsAsRevisionable::RevisionRecord.should_not_receive(:find)
372
385
  ActsAsRevisionable::RevisionRecord.should_not_receive(:delete_all)
373
386
  ActsAsRevisionable::RevisionRecord.truncate_revisions(TestRevisionableRecord, 1, :limit => nil, :minimum_age => nil)
374
387
  end
375
-
388
+
376
389
  it "should be able to find a record by revisioned type and id" do
377
390
  revision = ActsAsRevisionable::RevisionRecord.new(TestRevisionableRecord.new(:name => 'name'))
378
391
  ActsAsRevisionable::RevisionRecord.should_receive(:find).with(:first, :conditions => {:revisionable_type => 'TestRevisionableRecord', :revisionable_id => 1, :revision => 2}).and_return(revision)
379
392
  ActsAsRevisionable::RevisionRecord.find_revision(TestRevisionableRecord, 1, 2).should == revision
380
393
  end
381
394
 
395
+ it "should find the last revision" do
396
+ revision = ActsAsRevisionable::RevisionRecord.new(TestRevisionableRecord.new(:name => 'name'))
397
+ ActsAsRevisionable::RevisionRecord.should_receive(:find).with(:first, :conditions => {:revisionable_type => 'TestRevisionableRecord', :revisionable_id => 1}, :order => "revision DESC").and_return(revision)
398
+ ActsAsRevisionable::RevisionRecord.last_revision(TestRevisionableRecord, 1).should == revision
399
+ end
400
+
382
401
  it "should handle module namespaces" do
383
402
  attributes = {'id' => 1, 'name' => 'revision', 'value' => 5}
384
403
  revision = ActsAsRevisionable::RevisionRecord.new(ActsAsRevisionable::TestModuleRecord.new(attributes))
@@ -386,7 +405,7 @@ describe ActsAsRevisionable::RevisionRecord do
386
405
  restored = revision.restore
387
406
  restored.class.should == ActsAsRevisionable::TestModuleRecord
388
407
  end
389
-
408
+
390
409
  it "should handle single table inheritance" do
391
410
  attributes = {'id' => 1, 'name' => 'revision', 'value' => 5}
392
411
  record = TestInheritanceRecord.new(attributes)
@@ -395,34 +414,52 @@ describe ActsAsRevisionable::RevisionRecord do
395
414
  restored = revision.restore
396
415
  restored.class.should == TestInheritanceRecord
397
416
  end
398
-
417
+
399
418
  it "should really save the revision records to the database and restore without any mocking" do
400
- ActsAsRevisionable::RevisionRecord.delete_all
401
419
  ActsAsRevisionable::RevisionRecord.count.should == 0
402
-
403
- attributes = {'id' => 1, 'value' => rand(1000000)}
404
- original = TestRevisionableRecord.new(attributes)
405
- original.attributes['name'] = 'revision 1'
420
+
421
+ original = TestRevisionableRecord.create(:name => 'revision 1', :value => 100)
406
422
  ActsAsRevisionable::RevisionRecord.new(original).save!
407
- first_revision = ActsAsRevisionable::RevisionRecord.find(:first)
408
- original.attributes['name'] = 'revision 2'
423
+ first_revision = ActsAsRevisionable::RevisionRecord.first
424
+ original.name = 'revision 2'
409
425
  ActsAsRevisionable::RevisionRecord.new(original).save!
410
- original.attributes['name'] = 'revision 3'
426
+ original.name = 'revision 3'
411
427
  ActsAsRevisionable::RevisionRecord.new(original).save!
412
428
  ActsAsRevisionable::RevisionRecord.count.should == 3
413
-
414
- record = ActsAsRevisionable::RevisionRecord.find_revision(TestRevisionableRecord, 1, 1).restore
429
+
430
+ record = ActsAsRevisionable::RevisionRecord.find_revision(TestRevisionableRecord, original.id, 1).restore
415
431
  record.class.should == TestRevisionableRecord
416
- record.id.should == 1
417
- record.attributes.should == attributes.merge('name' => 'revision 1')
418
-
419
- ActsAsRevisionable::RevisionRecord.truncate_revisions(TestRevisionableRecord, 1, :limit => 2)
432
+ record.id.should == original.id
433
+ record.name.should == 'revision 1'
434
+ record.value.should == 100
435
+
436
+ ActsAsRevisionable::RevisionRecord.truncate_revisions(TestRevisionableRecord, original.id, :limit => 2)
420
437
  ActsAsRevisionable::RevisionRecord.count.should == 2
421
438
  ActsAsRevisionable::RevisionRecord.find_by_id(first_revision.id).should == nil
422
- ActsAsRevisionable::RevisionRecord.truncate_revisions(TestRevisionableRecord, 1, :limit => 0, :minimum_age => 1.week)
439
+ ActsAsRevisionable::RevisionRecord.truncate_revisions(TestRevisionableRecord, original.id, :limit => 0, :minimum_age => 1.week)
423
440
  ActsAsRevisionable::RevisionRecord.count.should == 2
424
- ActsAsRevisionable::RevisionRecord.truncate_revisions(TestRevisionableRecord, 1, :limit => 0)
441
+ ActsAsRevisionable::RevisionRecord.truncate_revisions(TestRevisionableRecord, original.id, :limit => 0)
425
442
  ActsAsRevisionable::RevisionRecord.count.should == 0
426
443
  end
427
444
 
445
+ it "should delete revisions for models in a class that no longer exist if they are older than a specified number of seconds" do
446
+ record_1 = TestRevisionableRecord.create(:name => 'record_1')
447
+ record_2 = TestRevisionableAssociationLegacyRecord.new(:name => 'record_2')
448
+ record_2.id = record_1.id
449
+ record_2.save!
450
+ revision_0 = ActsAsRevisionable::RevisionRecord.create(record_1)
451
+ revision_1 = ActsAsRevisionable::RevisionRecord.create(record_1)
452
+ revision_1.trash!
453
+ revision_2 = ActsAsRevisionable::RevisionRecord.create(record_2)
454
+ revision_2.trash!
455
+ revision_3 = ActsAsRevisionable::RevisionRecord.create(TestRevisionableRecord.create(:name => 'record_3'))
456
+ now = Time.now
457
+ Time.stub(:now => now + 60)
458
+ revision_4 = ActsAsRevisionable::RevisionRecord.create(TestRevisionableRecord.create(:name => 'record_4'))
459
+ revision_4.trash!
460
+ ActsAsRevisionable::RevisionRecord.count.should == 5
461
+ ActsAsRevisionable::RevisionRecord.empty_trash(TestRevisionableRecord, 30)
462
+ ActsAsRevisionable::RevisionRecord.count.should == 3
463
+ ActsAsRevisionable::RevisionRecord.all.collect{|r| r.id}.sort.should == [revision_2.id, revision_3.id, revision_4.id]
464
+ end
428
465
  end