copyable 0.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 +7 -0
- data/.gitignore +23 -0
- data/.rspec +2 -0
- data/.travis.yml +3 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +264 -0
- data/Rakefile +7 -0
- data/copyable.gemspec +28 -0
- data/lib/copyable.rb +32 -0
- data/lib/copyable/config.rb +19 -0
- data/lib/copyable/copy_registry.rb +50 -0
- data/lib/copyable/copyable_extension.rb +118 -0
- data/lib/copyable/declarations/after_copy.rb +15 -0
- data/lib/copyable/declarations/associations.rb +116 -0
- data/lib/copyable/declarations/columns.rb +34 -0
- data/lib/copyable/declarations/declaration.rb +15 -0
- data/lib/copyable/declarations/declarations.rb +14 -0
- data/lib/copyable/declarations/disable_all_callbacks_and_observers_except_validate.rb +9 -0
- data/lib/copyable/declarations/main.rb +32 -0
- data/lib/copyable/exceptions.rb +10 -0
- data/lib/copyable/model_hooks.rb +40 -0
- data/lib/copyable/option_checker.rb +23 -0
- data/lib/copyable/railtie.rb +9 -0
- data/lib/copyable/saver.rb +19 -0
- data/lib/copyable/single_copy_enforcer.rb +68 -0
- data/lib/copyable/syntax_checking/association_checker.rb +41 -0
- data/lib/copyable/syntax_checking/column_checker.rb +43 -0
- data/lib/copyable/syntax_checking/completeness_checker.rb +27 -0
- data/lib/copyable/syntax_checking/declaration_checker.rb +26 -0
- data/lib/copyable/syntax_checking/declaration_stubber.rb +18 -0
- data/lib/copyable/syntax_checking/syntax_checker.rb +15 -0
- data/lib/copyable/version.rb +3 -0
- data/lib/tasks/copyable.rake +55 -0
- data/spec/config_spec.rb +132 -0
- data/spec/copy_registry_spec.rb +55 -0
- data/spec/copyable_after_copy_spec.rb +28 -0
- data/spec/copyable_associations_spec.rb +366 -0
- data/spec/copyable_columns_spec.rb +116 -0
- data/spec/copyable_spec.rb +7 -0
- data/spec/create_copy_spec.rb +136 -0
- data/spec/deep_structure_copy_spec.rb +169 -0
- data/spec/helper/copyable_spec_helper.rb +15 -0
- data/spec/helper/test_models.rb +136 -0
- data/spec/helper/test_tables.rb +135 -0
- data/spec/model_hooks_spec.rb +66 -0
- data/spec/spec_helper.rb +29 -0
- data/spec/stress_test_spec.rb +261 -0
- data/spec/syntax_checking/association_checker_spec.rb +80 -0
- data/spec/syntax_checking/column_checker_spec.rb +49 -0
- data/spec/syntax_checking/declaration_checker_spec.rb +58 -0
- data/spec/syntax_checking_spec.rb +258 -0
- data/spec/transaction_spec.rb +78 -0
- metadata +200 -0
@@ -0,0 +1,116 @@
|
|
1
|
+
require_relative 'helper/copyable_spec_helper'
|
2
|
+
|
3
|
+
describe 'copyable:columns' do
|
4
|
+
context 'when asked to do a simple column copy' do
|
5
|
+
include ActiveSupport::Testing::TimeHelpers
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
undefine_copyable_in CopyableCoin
|
9
|
+
class CopyableCoin < ActiveRecord::Base
|
10
|
+
copyable do
|
11
|
+
disable_all_callbacks_and_observers_except_validate
|
12
|
+
columns({
|
13
|
+
kind: :copy,
|
14
|
+
year: :copy,
|
15
|
+
})
|
16
|
+
associations({
|
17
|
+
})
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should create a new record with matching columns' do
|
23
|
+
expect(CopyableCoin.count).to eq(0)
|
24
|
+
coin = CopyableCoin.create!(kind: 'cent', year: 1943)
|
25
|
+
coin.create_copy!
|
26
|
+
expect(CopyableCoin.where(kind: 'cent').count).to eq(2)
|
27
|
+
expect(CopyableCoin.where(year: 1943).count).to eq(2)
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should update timestamp columns' do
|
31
|
+
expect(CopyableCoin.count).to eq(0)
|
32
|
+
coin = CopyableCoin.create!(kind: 'cent', year: 1943)
|
33
|
+
travel_to 2.seconds.from_now do
|
34
|
+
coin_copy = coin.create_copy!
|
35
|
+
expect(coin_copy.updated_at).to be_present
|
36
|
+
expect(coin_copy.created_at).to be_present
|
37
|
+
expect(coin_copy.updated_at).not_to eq(coin.updated_at)
|
38
|
+
expect(coin_copy.created_at).not_to eq(coin.created_at)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'when asked to do a column copy with customization' do
|
44
|
+
before(:each) do
|
45
|
+
undefine_copyable_in CopyableCoin
|
46
|
+
class CopyableCoin < ActiveRecord::Base
|
47
|
+
copyable do
|
48
|
+
disable_all_callbacks_and_observers_except_validate
|
49
|
+
columns({
|
50
|
+
kind: lambda { |orig| "Copy of #{orig.kind}" },
|
51
|
+
year: :copy,
|
52
|
+
})
|
53
|
+
associations({
|
54
|
+
})
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
describe '#create_copy!' do
|
59
|
+
it 'should create a new record with the customized column' do
|
60
|
+
expect(CopyableCoin.count).to eq(0)
|
61
|
+
coin = CopyableCoin.create!(kind: 'quarter', year: 1964)
|
62
|
+
coin.create_copy!
|
63
|
+
expect(CopyableCoin.where(kind: 'quarter').count).to eq(1)
|
64
|
+
expect(CopyableCoin.where(kind: 'Copy of quarter').count).to eq(1)
|
65
|
+
expect(CopyableCoin.where(year: 1964).count).to eq(2)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'when asked to do a copy that produces invalid data' do
|
71
|
+
before(:each) do
|
72
|
+
undefine_copyable_in CopyableCoin
|
73
|
+
class CopyableCoin < ActiveRecord::Base
|
74
|
+
copyable do
|
75
|
+
disable_all_callbacks_and_observers_except_validate
|
76
|
+
columns({
|
77
|
+
kind: :copy,
|
78
|
+
year: lambda { |orig| -444 },
|
79
|
+
})
|
80
|
+
associations({
|
81
|
+
})
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
it 'should raise an error if data is not valid' do
|
86
|
+
expect(CopyableCoin.count).to eq(0)
|
87
|
+
coin = CopyableCoin.create!(kind: 'cent', year: 1982)
|
88
|
+
expect {
|
89
|
+
coin.create_copy!
|
90
|
+
}.to raise_error(ActiveRecord::RecordInvalid)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context 'with :do_not_copy advice' do
|
95
|
+
before(:each) do
|
96
|
+
undefine_copyable_in CopyableCoin
|
97
|
+
class CopyableCoin < ActiveRecord::Base
|
98
|
+
copyable do
|
99
|
+
disable_all_callbacks_and_observers_except_validate
|
100
|
+
columns({
|
101
|
+
kind: :do_not_copy,
|
102
|
+
year: :copy,
|
103
|
+
})
|
104
|
+
associations({
|
105
|
+
})
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
it 'should result in a nil value for that column' do
|
110
|
+
expect(CopyableCoin.count).to eq(0)
|
111
|
+
coin = CopyableCoin.create!(kind: 'cent', year: 1982)
|
112
|
+
copied_coin = coin.create_copy!
|
113
|
+
expect(copied_coin.kind).to be_nil
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require_relative 'helper/copyable_spec_helper'
|
2
|
+
|
3
|
+
describe 'create_copy!' do
|
4
|
+
before(:each) do
|
5
|
+
undefine_copyable_in CopyableCoin
|
6
|
+
class CopyableCoin < ActiveRecord::Base
|
7
|
+
copyable do
|
8
|
+
disable_all_callbacks_and_observers_except_validate
|
9
|
+
columns({
|
10
|
+
kind: :copy,
|
11
|
+
year: :copy,
|
12
|
+
})
|
13
|
+
associations({
|
14
|
+
})
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should exist' do
|
20
|
+
coin = CopyableCoin.create!(kind: 'cent', year: 1909)
|
21
|
+
expect(coin).to respond_to(:create_copy!)
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'should create a new record' do
|
25
|
+
expect(CopyableCoin.count).to eq(0)
|
26
|
+
coin = CopyableCoin.create!(kind: 'cent', year: 1909)
|
27
|
+
coin.create_copy!
|
28
|
+
expect(CopyableCoin.count).to eq(2)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should return the new record' do
|
32
|
+
expect(CopyableCoin.count).to eq(0)
|
33
|
+
coin = CopyableCoin.create!(kind: 'cent', year: 1909)
|
34
|
+
coin2 = coin.create_copy!
|
35
|
+
expect(coin2).to be_a CopyableCoin
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should return the new record having an id' do
|
39
|
+
expect(CopyableCoin.count).to eq(0)
|
40
|
+
coin = CopyableCoin.create!(kind: 'cent', year: 1909)
|
41
|
+
coin2 = coin.create_copy!
|
42
|
+
expect(coin2.id).not_to be_nil
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should allow columns to be overridden' do
|
46
|
+
expect(CopyableCoin.count).to eq(0)
|
47
|
+
coin = CopyableCoin.create!(kind: 'cent', year: 1909)
|
48
|
+
coin2 = coin.create_copy!(override: { year: 1959 })
|
49
|
+
expect(coin2.kind).to eq('cent')
|
50
|
+
expect(coin2.year).to eq(1959)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should allow columns to be overridden using strings as column names' do
|
54
|
+
expect(CopyableCoin.count).to eq(0)
|
55
|
+
coin = CopyableCoin.create!('kind' => 'cent', 'year' => 1909)
|
56
|
+
coin2 = coin.create_copy!(override: { 'year' => 1959 })
|
57
|
+
expect(coin2.kind).to eq('cent')
|
58
|
+
expect(coin2.year).to eq(1959)
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should allow validations to be skipped' do
|
62
|
+
coin = CopyableCoin.create!('kind' => 'cent', 'year' => 1909)
|
63
|
+
expect {
|
64
|
+
coin.create_copy!(override: { 'year' => 2 })
|
65
|
+
}.to raise_error(ActiveRecord::RecordInvalid)
|
66
|
+
expect {
|
67
|
+
coin.create_copy!(override: { 'year' => 2 }, skip_validations: true)
|
68
|
+
}.to_not raise_error
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should skip validations even in associated objects when skip_validations is true' do
|
72
|
+
# set up classes
|
73
|
+
undefine_copyable_in CopyablePet
|
74
|
+
class CopyablePet < ActiveRecord::Base
|
75
|
+
copyable do
|
76
|
+
disable_all_callbacks_and_observers_except_validate
|
77
|
+
columns({
|
78
|
+
name: :copy,
|
79
|
+
kind: :copy,
|
80
|
+
birth_year: :copy,
|
81
|
+
})
|
82
|
+
associations({
|
83
|
+
copyable_toys: :copy,
|
84
|
+
copyable_pet_tag: :do_not_copy,
|
85
|
+
copyable_pet_profile: :do_not_copy,
|
86
|
+
copyable_pet_foods: :do_not_copy,
|
87
|
+
copyable_pet_sitting_patronages: :do_not_copy,
|
88
|
+
})
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
undefine_copyable_in CopyableToy
|
93
|
+
class CopyableToy < ActiveRecord::Base
|
94
|
+
copyable do
|
95
|
+
disable_all_callbacks_and_observers_except_validate
|
96
|
+
columns({
|
97
|
+
name: :copy,
|
98
|
+
kind: :copy,
|
99
|
+
copyable_pet_id: :copy,
|
100
|
+
})
|
101
|
+
associations({
|
102
|
+
})
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
# set up objects
|
107
|
+
fido = CopyablePet.create!(
|
108
|
+
name: 'Fido',
|
109
|
+
kind: 'canine',
|
110
|
+
birth_year: 2005)
|
111
|
+
|
112
|
+
pillow = CopyableToy.create!(
|
113
|
+
name: 'favorite pillow',
|
114
|
+
kind: 'soft',
|
115
|
+
copyable_pet: fido)
|
116
|
+
|
117
|
+
# everything should be wonderful
|
118
|
+
expect {
|
119
|
+
fido.create_copy!
|
120
|
+
}.to_not raise_error
|
121
|
+
|
122
|
+
# now inject some invalid data in an associated object
|
123
|
+
pillow.update_column(:name, 'o')
|
124
|
+
fido.reload
|
125
|
+
|
126
|
+
# fail because invalid!
|
127
|
+
expect {
|
128
|
+
fido.create_copy!
|
129
|
+
}.to raise_error(ActiveRecord::RecordInvalid)
|
130
|
+
|
131
|
+
# oh quit complaning and do it anyway!
|
132
|
+
expect {
|
133
|
+
fido.create_copy!(skip_validations: true)
|
134
|
+
}.to_not raise_error
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
require_relative 'helper/copyable_spec_helper'
|
2
|
+
|
3
|
+
describe 'complex model hierarchies:' do
|
4
|
+
before(:each) do
|
5
|
+
undefine_copyable_in CopyableOwner
|
6
|
+
class CopyableOwner < ActiveRecord::Base
|
7
|
+
copyable do
|
8
|
+
disable_all_callbacks_and_observers_except_validate
|
9
|
+
columns({
|
10
|
+
name: :copy,
|
11
|
+
})
|
12
|
+
associations({
|
13
|
+
copyable_vehicles: :copy,
|
14
|
+
copyable_amenities: :copy,
|
15
|
+
})
|
16
|
+
end
|
17
|
+
end
|
18
|
+
undefine_copyable_in CopyableVehicle
|
19
|
+
class CopyableVehicle < ActiveRecord::Base
|
20
|
+
copyable do
|
21
|
+
disable_all_callbacks_and_observers_except_validate
|
22
|
+
columns({
|
23
|
+
name: :copy,
|
24
|
+
copyable_owner_id: :copy,
|
25
|
+
})
|
26
|
+
associations({
|
27
|
+
copyable_amenities: :copy,
|
28
|
+
})
|
29
|
+
end
|
30
|
+
end
|
31
|
+
undefine_copyable_in CopyableAmenity
|
32
|
+
class CopyableAmenity < ActiveRecord::Base
|
33
|
+
copyable do
|
34
|
+
disable_all_callbacks_and_observers_except_validate
|
35
|
+
columns({
|
36
|
+
name: :copy,
|
37
|
+
copyable_vehicle_id: :copy,
|
38
|
+
copyable_owner_id: :copy,
|
39
|
+
})
|
40
|
+
associations({
|
41
|
+
copyable_warranty: :copy,
|
42
|
+
})
|
43
|
+
end
|
44
|
+
end
|
45
|
+
undefine_copyable_in CopyableWarranty
|
46
|
+
class CopyableWarranty < ActiveRecord::Base
|
47
|
+
copyable do
|
48
|
+
disable_all_callbacks_and_observers_except_validate
|
49
|
+
columns({
|
50
|
+
name: :copy,
|
51
|
+
copyable_amenity_id: :copy,
|
52
|
+
})
|
53
|
+
associations({
|
54
|
+
})
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe 'a tree structure' do
|
60
|
+
before(:each) do
|
61
|
+
# We are avoiding using owners to avoid the denormalized aspect
|
62
|
+
# of the data model and keep this a simple tree.
|
63
|
+
@vehicle1 = CopyableVehicle.create!(name: 'Corvette')
|
64
|
+
|
65
|
+
@amenity1 = CopyableAmenity.create!(name: 'moon roof', copyable_vehicle: @vehicle1)
|
66
|
+
@warranty1 = CopyableWarranty.create!(name: 'moon roof warranty', copyable_amenity: @amenity1)
|
67
|
+
@amenity2 = CopyableAmenity.create!(name: 'twitter', copyable_vehicle: @vehicle1)
|
68
|
+
@warranty2 = CopyableWarranty.create!(name: 'twitter warranty', copyable_amenity: @amenity2)
|
69
|
+
@amenity3 = CopyableAmenity.create!(name: 'jazz', copyable_vehicle: @vehicle1)
|
70
|
+
@warranty3 = CopyableWarranty.create!(name: 'jazz warranty', copyable_amenity: @amenity3)
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'should copy the entire tree as directed' do
|
74
|
+
@vehicle2 = @vehicle1.create_copy!
|
75
|
+
expect(CopyableVehicle.count).to eq(2)
|
76
|
+
expect(CopyableAmenity.count).to eq(6)
|
77
|
+
expect(CopyableWarranty.count).to eq(6)
|
78
|
+
expect(@vehicle2.name).to eq('Corvette')
|
79
|
+
expect(@vehicle2.copyable_amenities.map(&:name)).to match_array(
|
80
|
+
['moon roof', 'twitter', 'jazz'])
|
81
|
+
expect(@vehicle2.copyable_amenities.map(&:copyable_warranty).map(&:name)).to match_array(
|
82
|
+
['moon roof warranty', 'twitter warranty', 'jazz warranty'])
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'should create the expected records if copied multiple times' do
|
86
|
+
# this test makes sure the SingleCopyEnforcer isn't too eager
|
87
|
+
@vehicle1.create_copy!
|
88
|
+
expect(CopyableVehicle.count).to eq(2)
|
89
|
+
expect(CopyableAmenity.count).to eq(6)
|
90
|
+
expect(CopyableWarranty.count).to eq(6)
|
91
|
+
@vehicle1.create_copy!
|
92
|
+
expect(CopyableVehicle.count).to eq(3)
|
93
|
+
expect(CopyableAmenity.count).to eq(9)
|
94
|
+
expect(CopyableWarranty.count).to eq(9)
|
95
|
+
@vehicle1.create_copy!
|
96
|
+
expect(CopyableVehicle.count).to eq(4)
|
97
|
+
expect(CopyableAmenity.count).to eq(12)
|
98
|
+
expect(CopyableWarranty.count).to eq(12)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
describe 'a denormalized structure' do
|
103
|
+
context 'having one redundant association' do
|
104
|
+
before(:each) do
|
105
|
+
@joe = CopyableOwner.create!(name: 'Joe')
|
106
|
+
@porsche = CopyableVehicle.create!(name: 'Porsche', copyable_owner: @joe)
|
107
|
+
@moon_roof = CopyableAmenity.create!(name: 'moon roof',
|
108
|
+
copyable_vehicle: @porsche,
|
109
|
+
copyable_owner: @joe)
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'should copy the records without copying any given record more than once' do
|
113
|
+
@copy_of_joe = @joe.create_copy!
|
114
|
+
expect(CopyableOwner.count).to eq(2)
|
115
|
+
expect(CopyableVehicle.count).to eq(2)
|
116
|
+
expect(CopyableAmenity.count).to eq(2)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context 'with many models, some having redundant associations' do
|
121
|
+
before(:each) do
|
122
|
+
@joe = CopyableOwner.create!(name: 'Joe')
|
123
|
+
|
124
|
+
@porsche = CopyableVehicle.create!(name: 'Porsche', copyable_owner: @joe)
|
125
|
+
@moon_roof = CopyableAmenity.create!(
|
126
|
+
name: 'moon roof',
|
127
|
+
copyable_vehicle: @porsche,
|
128
|
+
copyable_owner: @joe)
|
129
|
+
|
130
|
+
@mustang = CopyableVehicle.create!(name: 'Mustang', copyable_owner: @joe)
|
131
|
+
@air_conditioning = CopyableAmenity.create!(
|
132
|
+
name: 'air conditioning',
|
133
|
+
copyable_vehicle: @mustang,
|
134
|
+
copyable_owner: @joe)
|
135
|
+
@air_conditioning_warranty = CopyableWarranty.create!(
|
136
|
+
name: 'air conditioning warranty',
|
137
|
+
copyable_amenity: @air_conditioning)
|
138
|
+
|
139
|
+
@corvette = CopyableVehicle.create!(name: 'Corvette', copyable_owner: @joe)
|
140
|
+
@pillows = CopyableAmenity.create!(
|
141
|
+
name: 'pillows',
|
142
|
+
copyable_vehicle: @corvette,
|
143
|
+
copyable_owner: @joe)
|
144
|
+
@pillow_warranty = CopyableWarranty.create!(name: 'pillow warranty', copyable_amenity: @pillows)
|
145
|
+
@airbags = CopyableAmenity.create!(
|
146
|
+
name: 'airbags',
|
147
|
+
copyable_vehicle: @corvette,
|
148
|
+
copyable_owner: @joe)
|
149
|
+
@airbag_warranty = CopyableWarranty.create!(name: 'airbag warranty', copyable_amenity: @airbags)
|
150
|
+
@radio = CopyableAmenity.create!(
|
151
|
+
name: 'satellite radio',
|
152
|
+
copyable_vehicle: @corvette,
|
153
|
+
copyable_owner: @joe)
|
154
|
+
end
|
155
|
+
|
156
|
+
it 'should copy the records without copying any given record more than once' do
|
157
|
+
@copy_of_joe = @joe.create_copy!
|
158
|
+
expect(CopyableOwner.count).to eq(2)
|
159
|
+
expect(CopyableVehicle.count).to eq(6)
|
160
|
+
expect(CopyableAmenity.count).to eq(10)
|
161
|
+
expect(CopyableWarranty.count).to eq(6)
|
162
|
+
expect(@copy_of_joe.copyable_vehicles.map(&:name)).to match_array([
|
163
|
+
'Porsche', 'Mustang', 'Corvette'])
|
164
|
+
expect(@copy_of_joe.copyable_amenities.map(&:name)).to match_array([
|
165
|
+
'moon roof', 'air conditioning', 'pillows', 'airbags', 'satellite radio'])
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# copyable needs its own set of tables and ActiveRecord models to test with.
|
4
|
+
require_relative 'test_tables'
|
5
|
+
Copyable::TestTables.create!
|
6
|
+
require_relative 'test_models'
|
7
|
+
|
8
|
+
# useful for starting off specs with a clean slate
|
9
|
+
def undefine_copyable_in(klass)
|
10
|
+
klass.instance_eval do
|
11
|
+
define_method(:create_copy!) do |*args|
|
12
|
+
raise "the create_copy! method has been wiped clean for testing purposes"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
# We need various test models in various configurations to properly test the
|
2
|
+
# copying functionality.
|
3
|
+
|
4
|
+
|
5
|
+
#*******************************************************************************
|
6
|
+
# For testing basic copying behavior and validation.
|
7
|
+
#
|
8
|
+
|
9
|
+
class CopyableCoin < ActiveRecord::Base
|
10
|
+
validates :year, numericality: { greater_than: 1700 }
|
11
|
+
end
|
12
|
+
|
13
|
+
|
14
|
+
|
15
|
+
#*******************************************************************************
|
16
|
+
# For testing observers.
|
17
|
+
#
|
18
|
+
|
19
|
+
class CopyableCar < ActiveRecord::Base
|
20
|
+
validates :make, presence: true
|
21
|
+
validates :model, presence: true
|
22
|
+
validates :year, presence: true
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
#*******************************************************************************
|
28
|
+
# For testing callbacks.
|
29
|
+
#
|
30
|
+
|
31
|
+
class CopyableTree < ActiveRecord::Base
|
32
|
+
after_create :callback1
|
33
|
+
before_save { |tree| raise "callback2 called" }
|
34
|
+
def callback1
|
35
|
+
raise "callback1 called"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
#*******************************************************************************
|
42
|
+
# For testing basic associations.
|
43
|
+
#
|
44
|
+
|
45
|
+
class CopyablePet < ActiveRecord::Base
|
46
|
+
has_many :copyable_toys
|
47
|
+
has_one :copyable_pet_tag
|
48
|
+
has_one :copyable_pet_profile
|
49
|
+
has_one :copyable_address, through: :copyable_pet_profile
|
50
|
+
# Rails 3 expects the join table to be called copyable_pet_foods_copyable_pets
|
51
|
+
# Rails 4 expects the join table to be called copyable_pet_foods_pets
|
52
|
+
# We explicitly name the join table so that this code works with both Rails 3 and Rails 4.
|
53
|
+
has_and_belongs_to_many :copyable_pet_foods, join_table: 'copyable_pet_foods_pets'
|
54
|
+
has_many :copyable_pet_sitting_patronages
|
55
|
+
has_many :copyable_pet_sitters, through: :copyable_pet_sitting_patronages
|
56
|
+
end
|
57
|
+
|
58
|
+
class CopyableToy < ActiveRecord::Base
|
59
|
+
validates :name, length: { minimum: 3 }
|
60
|
+
belongs_to :copyable_pet
|
61
|
+
end
|
62
|
+
|
63
|
+
class CopyablePetTag < ActiveRecord::Base
|
64
|
+
belongs_to :copyable_pet
|
65
|
+
end
|
66
|
+
|
67
|
+
class CopyablePetFood < ActiveRecord::Base
|
68
|
+
# Rails 3 expects the join table to be called copyable_pet_foods_copyable_pets
|
69
|
+
# Rails 4 expects the join table to be called copyable_pet_foods_pets
|
70
|
+
# We explicitly name the join table so that this code works with both Rails 3 and Rails 4.
|
71
|
+
has_and_belongs_to_many :copyable_pets, join_table: 'copyable_pet_foods_pets'
|
72
|
+
end
|
73
|
+
|
74
|
+
class CopyablePetSitter < ActiveRecord::Base
|
75
|
+
has_many :copyable_pet_sitting_patronages
|
76
|
+
has_many :copyable_pets, through: :copyable_pet_sitting_patronages
|
77
|
+
end
|
78
|
+
|
79
|
+
class CopyablePetSittingPatronage < ActiveRecord::Base
|
80
|
+
belongs_to :copyable_pet
|
81
|
+
belongs_to :copyable_pet_sitter
|
82
|
+
end
|
83
|
+
|
84
|
+
class CopyablePetProfile < ActiveRecord::Base
|
85
|
+
belongs_to :copyable_pet
|
86
|
+
has_one :copyable_address
|
87
|
+
end
|
88
|
+
|
89
|
+
class CopyableAddress < ActiveRecord::Base
|
90
|
+
belongs_to :copyable_pet_profile
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
|
95
|
+
#*******************************************************************************
|
96
|
+
# For testing polymorphic associations and custom-named foreign keys.
|
97
|
+
#
|
98
|
+
|
99
|
+
class CopyablePicture < ActiveRecord::Base
|
100
|
+
belongs_to :imageable, polymorphic: true
|
101
|
+
belongs_to :copyable_album, foreign_key: 'picture_album_id'
|
102
|
+
end
|
103
|
+
|
104
|
+
class CopyableProduct < ActiveRecord::Base
|
105
|
+
has_many :copyable_pictures, as: :imageable
|
106
|
+
end
|
107
|
+
|
108
|
+
class CopyableAlbum < ActiveRecord::Base
|
109
|
+
has_many :copyable_pictures, foreign_key: 'picture_album_id'
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
|
114
|
+
#*******************************************************************************
|
115
|
+
# For testing denormalized data structures.
|
116
|
+
#
|
117
|
+
|
118
|
+
class CopyableOwner < ActiveRecord::Base
|
119
|
+
has_many :copyable_vehicles
|
120
|
+
has_many :copyable_amenities # this is not normalized, you wouldn't normally do this
|
121
|
+
end
|
122
|
+
|
123
|
+
class CopyableVehicle < ActiveRecord::Base
|
124
|
+
has_many :copyable_amenities
|
125
|
+
belongs_to :copyable_owner
|
126
|
+
end
|
127
|
+
|
128
|
+
class CopyableAmenity < ActiveRecord::Base
|
129
|
+
belongs_to :copyable_vehicle
|
130
|
+
belongs_to :copyable_owner # this is not normalized, you wouldn't normally do this
|
131
|
+
has_one :copyable_warranty
|
132
|
+
end
|
133
|
+
|
134
|
+
class CopyableWarranty < ActiveRecord::Base
|
135
|
+
belongs_to :copyable_amenity
|
136
|
+
end
|