copyable 0.1.1 → 0.3.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 +5 -5
- data/README.md +4 -11
- data/copyable.gemspec +6 -6
- data/lib/copyable/copyable_extension.rb +3 -1
- data/lib/copyable/declarations/associations.rb +13 -10
- data/lib/copyable/model_hooks.rb +20 -17
- data/lib/copyable/option_checker.rb +1 -1
- data/lib/copyable/saver.rb +19 -11
- data/lib/copyable/syntax_checking/association_checker.rb +2 -1
- data/lib/copyable/version.rb +1 -1
- data/lib/tasks/copyable.rake +2 -1
- data/spec/deep_structure_copy_spec.rb +21 -0
- data/spec/helper/test_tables.rb +18 -18
- data/spec/model_hooks_spec.rb +10 -64
- metadata +25 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 2a08309e56270ce4847101314203835381cb28e1ece99a477391cc23461e3d78
|
4
|
+
data.tar.gz: 440110e69f8828d034ba8b01dcbae7bc56e011aea751a69f202423ffa66859f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 65fd03e6dce5bfd47f6aa2f784f4a8cab6d061ad6d3c693609239a848af4867bae34cded904a9c540041631cc456b636c44e70e0b6c6a8ab94fe0e07f2e197a9
|
7
|
+
data.tar.gz: '0585f34ccded08588ad09aa76a13834846c17c082a783da6f4f4f96f80d3d96156f54437022edf62c521eda8202e06fa02d5b8f24ddc921b401cf4251d591891'
|
data/README.md
CHANGED
@@ -121,16 +121,9 @@ The advice must be one of the following:
|
|
121
121
|
|
122
122
|
## Callbacks
|
123
123
|
|
124
|
-
It depends on the situation as to whether you would want a particular callback to be fired when a model is copied. Since the logic of callbacks is situational, Copyable makes the decision to
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
copyable do
|
129
|
-
disable_all_callbacks_and_observers_except_validate
|
130
|
-
...
|
131
|
-
end
|
132
|
-
|
133
|
-
|
124
|
+
It depends on the situation as to whether you would want a particular callback to be fired when a model is copied. Since the logic of callbacks is situational, Copyable makes the decision to bypass callbacks
|
125
|
+
when saving the copied models by using raw SQL insert statements during the copy. It will check
|
126
|
+
validations unless `skip_validations` is passed to `create_copy`.
|
134
127
|
|
135
128
|
## The After Copy Declaration
|
136
129
|
|
@@ -267,4 +260,4 @@ So the recommended approach is to use `after_copy` to tweak the columns of the c
|
|
267
260
|
|
268
261
|
## About
|
269
262
|
|
270
|
-
Copyable was developed at [District Management Group](https://dmgroupK12.com).
|
263
|
+
Copyable was developed at [District Management Group](https://dmgroupK12.com).
|
data/copyable.gemspec
CHANGED
@@ -6,8 +6,8 @@ require 'copyable/version'
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "copyable"
|
8
8
|
spec.version = Copyable::VERSION
|
9
|
-
spec.authors = ["Wyatt Greene", "Dennis Chan"]
|
10
|
-
spec.email = ["dchan@
|
9
|
+
spec.authors = ["Wyatt Greene", "Dennis Chan", "Anne Geiersbach", "Parker Morse"]
|
10
|
+
spec.email = ["dchan@dmgroupK12.com", "ageiersbach@dmgroupK12.com", "pmorse@dmgroupK12.com"]
|
11
11
|
spec.summary = %q{ActiveRecord copier}
|
12
12
|
spec.description = %q{Copyable makes it easy to copy ActiveRecord models.}
|
13
13
|
spec.homepage = "https://github.com/dmcouncil/copyable"
|
@@ -18,11 +18,11 @@ Gem::Specification.new do |spec|
|
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ["lib"]
|
20
20
|
|
21
|
-
spec.add_dependency "activerecord", "
|
21
|
+
spec.add_dependency "activerecord", "5.2.6"
|
22
22
|
|
23
|
-
spec.add_development_dependency "database_cleaner", "~>
|
24
|
-
spec.add_development_dependency "bundler"
|
23
|
+
spec.add_development_dependency "database_cleaner", "~> 2"
|
24
|
+
spec.add_development_dependency "bundler"
|
25
25
|
spec.add_development_dependency "rake"
|
26
26
|
spec.add_development_dependency "rspec"
|
27
|
-
spec.add_development_dependency "sqlite3"
|
27
|
+
spec.add_development_dependency "sqlite3", "~> 1.3.6"
|
28
28
|
end
|
@@ -49,6 +49,8 @@ module Copyable
|
|
49
49
|
# fill in each column of this brand new model according to the
|
50
50
|
# instructions given in the copyable declaration
|
51
51
|
column_overrides = options[:override] || {}
|
52
|
+
# merge with global override hash if exists
|
53
|
+
column_overrides = column_overrides.merge(options[:global_override]) if options[:global_override]
|
52
54
|
Declarations::Columns.execute(main.column_list, original_model, new_model, column_overrides)
|
53
55
|
# save that sucker!
|
54
56
|
Copyable::Saver.save!(new_model, options[:skip_validations])
|
@@ -61,7 +63,7 @@ module Copyable
|
|
61
63
|
# declaration
|
62
64
|
|
63
65
|
skip_associations = options[:skip_associations] || []
|
64
|
-
Declarations::Associations.execute(main.association_list, original_model, new_model, options[:skip_validations], skip_associations)
|
66
|
+
Declarations::Associations.execute(main.association_list, original_model, new_model, options[:global_override], options[:skip_validations], skip_associations)
|
65
67
|
# run the after_copy block if it exists
|
66
68
|
Declarations::AfterCopy.execute(main.after_copy_block, original_model, new_model)
|
67
69
|
ensure
|
@@ -6,10 +6,12 @@ module Copyable
|
|
6
6
|
|
7
7
|
# this is the algorithm for copying associated records according to the
|
8
8
|
# instructions given in the copyable declaration
|
9
|
-
def execute(association_list, original_model, new_model, skip_validations, skip_associations)
|
9
|
+
def execute(association_list, original_model, new_model, global_override = {}, skip_validations, skip_associations)
|
10
10
|
@skip_validations = skip_validations
|
11
|
+
@skip_associations = skip_associations
|
12
|
+
@global_override = global_override
|
11
13
|
association_list.each do |assoc_name, advice|
|
12
|
-
association = original_model.class.reflections[assoc_name.
|
14
|
+
association = original_model.class.reflections[assoc_name.to_s]
|
13
15
|
check_advice(association, advice, original_model)
|
14
16
|
unless advice == :do_not_copy || skip_associations.include?(assoc_name.to_sym)
|
15
17
|
copy_association(association, original_model, new_model)
|
@@ -26,14 +28,14 @@ module Copyable
|
|
26
28
|
message << "has unrecognized advice '#{advice}'."
|
27
29
|
raise AssociationError.new(message)
|
28
30
|
end
|
29
|
-
if association.
|
31
|
+
if association.is_a?(ActiveRecord::Reflection::HasAndBelongsToManyReflection) && advice == :copy
|
30
32
|
message = "Error in copyable:associations of "
|
31
33
|
message << "#{original_model.class.name}: the association '#{association.name}' "
|
32
34
|
message << "only supports the :copy_only_habtm_join_records advice, not the :copy advice, "
|
33
35
|
message << "because it is a has_and_belongs_to_many association."
|
34
36
|
raise AssociationError.new(message)
|
35
37
|
end
|
36
|
-
if association.
|
38
|
+
if !association.is_a?(ActiveRecord::Reflection::HasAndBelongsToManyReflection) && advice == :copy_only_habtm_join_records
|
37
39
|
message = "Error in copyable:associations of "
|
38
40
|
message << "#{original_model.class.name}: the association '#{association.name}' "
|
39
41
|
message << "only supports the :copy advice, not the :copy_only_habtm_join_records advice, "
|
@@ -43,15 +45,14 @@ module Copyable
|
|
43
45
|
end
|
44
46
|
|
45
47
|
def copy_association(association, original_model, new_model)
|
46
|
-
|
47
|
-
when :has_many
|
48
|
+
if association.is_a?(ActiveRecord::Reflection::HasManyReflection)
|
48
49
|
copy_has_many(association, original_model, new_model)
|
49
|
-
|
50
|
+
elsif association.is_a?(ActiveRecord::Reflection::HasOneReflection)
|
50
51
|
copy_has_one(association, original_model, new_model)
|
51
|
-
|
52
|
+
elsif association.is_a?(ActiveRecord::Reflection::HasAndBelongsToManyReflection)
|
52
53
|
copy_habtm(association, original_model, new_model)
|
53
54
|
else
|
54
|
-
raise "Unsupported association #{association.
|
55
|
+
raise "Unsupported association #{association.class}" # should never happen, since we filter out belongs_to
|
55
56
|
end
|
56
57
|
end
|
57
58
|
|
@@ -78,7 +79,9 @@ module Copyable
|
|
78
79
|
copied_record = original_record.create_copy!(
|
79
80
|
override: { association.foreign_key => parent_model.id },
|
80
81
|
__called_recursively: true,
|
81
|
-
|
82
|
+
global_override: @global_override,
|
83
|
+
skip_validations: @skip_validations,
|
84
|
+
skip_associations: @skip_associations)
|
82
85
|
else
|
83
86
|
message = "Could not copy #{parent_model.class.name}#id:#{parent_model.id} "
|
84
87
|
message << "because #{original_record.class.name} does not have a copyable declaration."
|
data/lib/copyable/model_hooks.rb
CHANGED
@@ -16,30 +16,33 @@ module Copyable
|
|
16
16
|
|
17
17
|
def self.disable_all_callbacks(klass)
|
18
18
|
klass.class_eval do
|
19
|
-
# Don't do
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
19
|
+
return if self.method_defined? :old_save! # Don't do this more than once
|
20
|
+
|
21
|
+
@all_callbacks_disabled = true
|
22
|
+
class << self
|
23
|
+
attr_reader :all_callbacks_disabled
|
24
|
+
end
|
25
|
+
|
26
|
+
alias_method :old_save!, :save!
|
27
|
+
|
28
|
+
# Hold my beer while we bypass all the Rails callbacks
|
29
|
+
# in favor of some raw SQL
|
30
|
+
def save!
|
31
|
+
Copyable::Saver.save!(self)
|
32
32
|
end
|
33
33
|
end
|
34
34
|
end
|
35
35
|
|
36
36
|
def self.reenable_all_callbacks(klass)
|
37
37
|
klass.class_eval do
|
38
|
-
|
39
|
-
|
38
|
+
return unless self.method_defined? :old_save! # Don't do this more than once
|
39
|
+
@all_callbacks_disabled = false
|
40
|
+
class << self
|
41
|
+
attr_reader :all_callbacks_disabled
|
42
|
+
end
|
40
43
|
|
41
|
-
alias_method :
|
42
|
-
remove_method :
|
44
|
+
alias_method :save!, :old_save!
|
45
|
+
remove_method :old_save!
|
43
46
|
end
|
44
47
|
end
|
45
48
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Copyable
|
2
2
|
class OptionChecker
|
3
3
|
|
4
|
-
VALID_OPTIONS = [:override, :skip_validations, :skip_associations]
|
4
|
+
VALID_OPTIONS = [:override, :global_override, :skip_validations, :skip_associations]
|
5
5
|
VALID_PRIVATE_OPTIONS = [:__called_recursively] # for copyable's internal use only
|
6
6
|
|
7
7
|
def self.check!(options)
|
data/lib/copyable/saver.rb
CHANGED
@@ -1,19 +1,27 @@
|
|
1
1
|
module Copyable
|
2
2
|
class Saver
|
3
3
|
|
4
|
+
def self.direct_sql_insert!(new_model)
|
5
|
+
new_model.send(:_create_record) # bypass all callbacks and validations
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.direct_sql_update!(new_model)
|
9
|
+
new_model.send(:_update_record) # bypass all callbacks and validations
|
10
|
+
end
|
11
|
+
|
4
12
|
# this is the algorithm for saving the new record
|
5
|
-
def self.save!(new_model, skip_validations)
|
6
|
-
unless skip_validations
|
7
|
-
|
8
|
-
if !new_model.valid?(:create)
|
9
|
-
ModelHooks.disable!(new_model.class)
|
10
|
-
raise(ActiveRecord::RecordInvalid.new(new_model))
|
11
|
-
else
|
12
|
-
ModelHooks.disable!(new_model.class)
|
13
|
-
end
|
13
|
+
def self.save!(new_model, skip_validations=false)
|
14
|
+
unless skip_validations || new_model.valid?(:create)
|
15
|
+
raise(ActiveRecord::RecordInvalid.new(new_model))
|
14
16
|
end
|
15
|
-
new_model.save!
|
16
|
-
end
|
17
17
|
|
18
|
+
if new_model.class.all_callbacks_disabled && new_model.id.nil?
|
19
|
+
self.direct_sql_insert!(new_model)
|
20
|
+
elsif new_model.class.all_callbacks_disabled
|
21
|
+
self.direct_sql_update!(new_model)
|
22
|
+
else
|
23
|
+
new_model.save!
|
24
|
+
end
|
25
|
+
end
|
18
26
|
end
|
19
27
|
end
|
@@ -10,7 +10,8 @@ module Copyable
|
|
10
10
|
def expected_entries
|
11
11
|
all_associations = model_class.reflect_on_all_associations
|
12
12
|
required_associations = all_associations.select do |ass|
|
13
|
-
|
13
|
+
!ass.is_a?(ActiveRecord::Reflection::BelongsToReflection) &&
|
14
|
+
!ass.is_a?(ActiveRecord::Reflection::ThroughReflection)
|
14
15
|
end
|
15
16
|
required_associations.map(&:name).map(&:to_s)
|
16
17
|
end
|
data/lib/copyable/version.rb
CHANGED
data/lib/tasks/copyable.rake
CHANGED
@@ -39,7 +39,8 @@ task :copyable => :environment do
|
|
39
39
|
|
40
40
|
all_associations = model_class.reflect_on_all_associations
|
41
41
|
required_associations = all_associations.select do |ass|
|
42
|
-
|
42
|
+
!ass.is_a?(ActiveRecord::Reflection::BelongsToReflection) &&
|
43
|
+
!ass.is_a?(ActiveRecord::Reflection::ThroughReflection)
|
43
44
|
end
|
44
45
|
associations = required_associations.map(&:name).map(&:to_s)
|
45
46
|
max_length = associations.map(&:length).max
|
@@ -89,6 +89,13 @@ describe 'complex model hierarchies:' do
|
|
89
89
|
expect(CopyableWarranty.count).to eq(3) # Because the amenities weren't copied either
|
90
90
|
end
|
91
91
|
|
92
|
+
it 'should skip nested branches of the tree when directed' do
|
93
|
+
@vehicle2 = @vehicle1.create_copy!(skip_associations: [:copyable_warranty])
|
94
|
+
expect(CopyableVehicle.count).to eq(2)
|
95
|
+
expect(CopyableAmenity.count).to eq(6)
|
96
|
+
expect(CopyableWarranty.count).to eq(3) # No new ones created
|
97
|
+
end
|
98
|
+
|
92
99
|
it 'should create the expected records if copied multiple times' do
|
93
100
|
# this test makes sure the SingleCopyEnforcer isn't too eager
|
94
101
|
@vehicle1.create_copy!
|
@@ -122,6 +129,20 @@ describe 'complex model hierarchies:' do
|
|
122
129
|
expect(CopyableVehicle.count).to eq(2)
|
123
130
|
expect(CopyableAmenity.count).to eq(2)
|
124
131
|
end
|
132
|
+
|
133
|
+
context 'with a global override, can copy vehicle with new owner' do
|
134
|
+
before(:each) do
|
135
|
+
@jane = CopyableOwner.create!(name: 'Jane')
|
136
|
+
end
|
137
|
+
|
138
|
+
it 'should copy the records correctly' do
|
139
|
+
@copy_of_joes_car = @porsche.create_copy!(global_override: { copyable_owner_id: @jane.id })
|
140
|
+
expect(CopyableVehicle.count).to eq(2)
|
141
|
+
expect(CopyableAmenity.count).to eq(2)
|
142
|
+
expect(@copy_of_joes_car.copyable_owner_id).to eq(@jane.id)
|
143
|
+
expect(@copy_of_joes_car.copyable_amenities.map(&:copyable_owner_id).uniq).to eq([@jane.id])
|
144
|
+
end
|
145
|
+
end
|
125
146
|
end
|
126
147
|
|
127
148
|
context 'with many models, some having redundant associations' do
|
data/spec/helper/test_tables.rb
CHANGED
@@ -11,14 +11,14 @@ module Copyable
|
|
11
11
|
|
12
12
|
create_table :copyable_albums, force: true do |t|
|
13
13
|
t.string :name, null: false
|
14
|
-
t.timestamps
|
14
|
+
t.timestamps null: false
|
15
15
|
end
|
16
16
|
|
17
17
|
create_table :copyable_amenities, force: true do |t|
|
18
18
|
t.string :name
|
19
19
|
t.integer :copyable_vehicle_id
|
20
20
|
t.integer :copyable_owner_id
|
21
|
-
t.timestamps
|
21
|
+
t.timestamps null: false
|
22
22
|
end
|
23
23
|
|
24
24
|
create_table :copyable_addresses, force: true do |t|
|
@@ -27,30 +27,30 @@ module Copyable
|
|
27
27
|
t.string :city, null: false
|
28
28
|
t.string :state, null: false
|
29
29
|
t.integer :copyable_pet_profile_id, null: false
|
30
|
-
t.timestamps
|
30
|
+
t.timestamps null: false
|
31
31
|
end
|
32
32
|
|
33
33
|
create_table :copyable_cars, force: true do |t|
|
34
34
|
t.string :make, null: false
|
35
35
|
t.string :model, null: false
|
36
36
|
t.integer :year, null: false
|
37
|
-
t.timestamps
|
37
|
+
t.timestamps null: false
|
38
38
|
end
|
39
39
|
|
40
40
|
create_table :copyable_coins, force: true do |t|
|
41
41
|
t.string :kind
|
42
42
|
t.integer :year
|
43
|
-
t.timestamps
|
43
|
+
t.timestamps null: false
|
44
44
|
end
|
45
45
|
|
46
46
|
create_table :copyable_owners, force: true do |t|
|
47
47
|
t.string :name, null: false
|
48
|
-
t.timestamps
|
48
|
+
t.timestamps null: false
|
49
49
|
end
|
50
50
|
|
51
51
|
create_table :copyable_pet_foods, force: true do |t|
|
52
52
|
t.string :name, null: false
|
53
|
-
t.timestamps
|
53
|
+
t.timestamps null: false
|
54
54
|
end
|
55
55
|
|
56
56
|
create_table :copyable_pet_foods_pets, force: true, id: false do |t|
|
@@ -62,31 +62,31 @@ module Copyable
|
|
62
62
|
t.string :description, null: false
|
63
63
|
t.string :nickname
|
64
64
|
t.integer :copyable_pet_id, null: false
|
65
|
-
t.timestamps
|
65
|
+
t.timestamps null: false
|
66
66
|
end
|
67
67
|
|
68
68
|
create_table :copyable_pet_sitters, force: true do |t|
|
69
69
|
t.string :name, null: false
|
70
|
-
t.timestamps
|
70
|
+
t.timestamps null: false
|
71
71
|
end
|
72
72
|
|
73
73
|
create_table :copyable_pet_sitting_patronages, force: true do |t|
|
74
74
|
t.integer :copyable_pet_id, null: false
|
75
75
|
t.integer :copyable_pet_sitter_id, null: false
|
76
|
-
t.timestamps
|
76
|
+
t.timestamps null: false
|
77
77
|
end
|
78
78
|
|
79
79
|
create_table :copyable_pet_tags, force: true do |t|
|
80
80
|
t.string :registered_name, null: false
|
81
81
|
t.integer :copyable_pet_id, null: false
|
82
|
-
t.timestamps
|
82
|
+
t.timestamps null: false
|
83
83
|
end
|
84
84
|
|
85
85
|
create_table :copyable_pets, force: true do |t|
|
86
86
|
t.string :name, null: false
|
87
87
|
t.string :kind, null: false
|
88
88
|
t.integer :birth_year
|
89
|
-
t.timestamps
|
89
|
+
t.timestamps null: false
|
90
90
|
end
|
91
91
|
|
92
92
|
create_table :copyable_pictures, force: true do |t|
|
@@ -94,36 +94,36 @@ module Copyable
|
|
94
94
|
t.integer :imageable_id
|
95
95
|
t.string :imageable_type
|
96
96
|
t.integer :picture_album_id
|
97
|
-
t.timestamps
|
97
|
+
t.timestamps null: false
|
98
98
|
end
|
99
99
|
|
100
100
|
create_table :copyable_products, force: true do |t|
|
101
101
|
t.string :name
|
102
|
-
t.timestamps
|
102
|
+
t.timestamps null: false
|
103
103
|
end
|
104
104
|
|
105
105
|
create_table :copyable_toys, force: true do |t|
|
106
106
|
t.string :name
|
107
107
|
t.string :kind
|
108
108
|
t.integer :copyable_pet_id
|
109
|
-
t.timestamps
|
109
|
+
t.timestamps null: false
|
110
110
|
end
|
111
111
|
|
112
112
|
create_table :copyable_trees, force: true do |t|
|
113
113
|
t.string :kind
|
114
|
-
t.timestamps
|
114
|
+
t.timestamps null: false
|
115
115
|
end
|
116
116
|
|
117
117
|
create_table :copyable_vehicles, force: true do |t|
|
118
118
|
t.string :name
|
119
119
|
t.integer :copyable_owner_id
|
120
|
-
t.timestamps
|
120
|
+
t.timestamps null: false
|
121
121
|
end
|
122
122
|
|
123
123
|
create_table :copyable_warranties, force: true do |t|
|
124
124
|
t.string :name
|
125
125
|
t.integer :copyable_amenity_id
|
126
|
-
t.timestamps
|
126
|
+
t.timestamps null: false
|
127
127
|
end
|
128
128
|
|
129
129
|
end
|
data/spec/model_hooks_spec.rb
CHANGED
@@ -9,85 +9,31 @@ describe Copyable::ModelHooks do
|
|
9
9
|
before(:each) do
|
10
10
|
Copyable::ModelHooks.disable!(CopyableTree)
|
11
11
|
end
|
12
|
+
|
12
13
|
after(:each) do
|
13
14
|
Copyable::ModelHooks.reenable!(CopyableTree)
|
14
15
|
end
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
}.to_not raise_error
|
16
|
+
|
17
|
+
it 'defines an instance variable on the class' do
|
18
|
+
expect(CopyableTree.all_callbacks_disabled).to eq(true)
|
19
19
|
end
|
20
|
+
|
20
21
|
it 'should not prevent model actions from executing' do
|
21
22
|
expect(CopyableTree.count).to eq(0)
|
22
|
-
CopyableTree.create!(kind: 'magnolia')
|
23
|
-
expect(CopyableTree.count).to eq(1)
|
24
23
|
end
|
25
24
|
end
|
26
25
|
|
27
26
|
describe '.reenable!' do
|
28
|
-
it '
|
29
|
-
Copyable::ModelHooks.disable!(CopyableTree)
|
27
|
+
it 'defines an instance variable on the class' do
|
30
28
|
Copyable::ModelHooks.reenable!(CopyableTree)
|
31
|
-
expect
|
32
|
-
CopyableTree.create!(kind: 'magnolia')
|
33
|
-
}.to raise_error(RuntimeError, "callback2 called")
|
29
|
+
expect(CopyableTree.all_callbacks_disabled).to eq(false)
|
34
30
|
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
context 'validations' do
|
39
31
|
|
40
|
-
|
41
|
-
|
42
|
-
describe '.disable!' do
|
43
|
-
before(:each) do
|
44
|
-
Copyable::ModelHooks.disable!(CopyableCoin)
|
45
|
-
end
|
46
|
-
after(:each) do
|
47
|
-
Copyable::ModelHooks.reenable!(CopyableCoin)
|
48
|
-
end
|
49
|
-
it 'should prevent validations from executing' do
|
50
|
-
expect {
|
51
|
-
CopyableCoin.create!(year: -10)
|
52
|
-
}.to_not raise_error
|
53
|
-
end
|
54
|
-
it 'should not prevent model actions from executing' do
|
55
|
-
expect(CopyableCoin.count).to eq(0)
|
56
|
-
CopyableCoin.create!(year: -10)
|
57
|
-
expect(CopyableCoin.count).to eq(1)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
describe '.reenable!' do
|
62
|
-
it 'should allow validations to execute again' do
|
63
|
-
Copyable::ModelHooks.disable!(CopyableCoin)
|
64
|
-
Copyable::ModelHooks.reenable!(CopyableCoin)
|
32
|
+
it 'should allow callbacks to execute again' do
|
65
33
|
expect {
|
66
|
-
|
67
|
-
}.to raise_error(
|
34
|
+
CopyableTree.create!(kind: 'magnolia')
|
35
|
+
}.to raise_error(RuntimeError, "callback2 called")
|
68
36
|
end
|
69
37
|
end
|
70
38
|
end
|
71
|
-
|
72
|
-
describe 'nested disables and enables' do
|
73
|
-
it 'should allow callbacks to execute again' do
|
74
|
-
Copyable::ModelHooks.disable!(CopyableTree)
|
75
|
-
expect { CopyableTree.create!(kind: 'magnolia') }.to_not raise_error
|
76
|
-
|
77
|
-
Copyable::ModelHooks.disable!(CopyableCoin)
|
78
|
-
expect { CopyableCoin.create!(year: -10) }.to_not raise_error
|
79
|
-
|
80
|
-
Copyable::ModelHooks.disable!(CopyableTree)
|
81
|
-
expect { CopyableTree.create!(kind: 'magnolia') }.to_not raise_error
|
82
|
-
|
83
|
-
Copyable::ModelHooks.reenable!(CopyableCoin)
|
84
|
-
expect { CopyableCoin.create!(year: -10) }.to raise_error(ActiveRecord::RecordInvalid)
|
85
|
-
|
86
|
-
Copyable::ModelHooks.reenable!(CopyableTree)
|
87
|
-
expect { CopyableTree.create!(kind: 'magnolia') }.to raise_error(RuntimeError)
|
88
|
-
|
89
|
-
Copyable::ModelHooks.reenable!(CopyableTree)
|
90
|
-
expect { CopyableTree.create!(kind: 'magnolia') }.to raise_error(RuntimeError)
|
91
|
-
end
|
92
|
-
end
|
93
39
|
end
|
metadata
CHANGED
@@ -1,58 +1,60 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: copyable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wyatt Greene
|
8
8
|
- Dennis Chan
|
9
|
-
|
9
|
+
- Anne Geiersbach
|
10
|
+
- Parker Morse
|
11
|
+
autorequire:
|
10
12
|
bindir: bin
|
11
13
|
cert_chain: []
|
12
|
-
date:
|
14
|
+
date: 2021-08-18 00:00:00.000000000 Z
|
13
15
|
dependencies:
|
14
16
|
- !ruby/object:Gem::Dependency
|
15
17
|
name: activerecord
|
16
18
|
requirement: !ruby/object:Gem::Requirement
|
17
19
|
requirements:
|
18
|
-
- -
|
20
|
+
- - '='
|
19
21
|
- !ruby/object:Gem::Version
|
20
|
-
version:
|
22
|
+
version: 5.2.6
|
21
23
|
type: :runtime
|
22
24
|
prerelease: false
|
23
25
|
version_requirements: !ruby/object:Gem::Requirement
|
24
26
|
requirements:
|
25
|
-
- -
|
27
|
+
- - '='
|
26
28
|
- !ruby/object:Gem::Version
|
27
|
-
version:
|
29
|
+
version: 5.2.6
|
28
30
|
- !ruby/object:Gem::Dependency
|
29
31
|
name: database_cleaner
|
30
32
|
requirement: !ruby/object:Gem::Requirement
|
31
33
|
requirements:
|
32
34
|
- - "~>"
|
33
35
|
- !ruby/object:Gem::Version
|
34
|
-
version:
|
36
|
+
version: '2'
|
35
37
|
type: :development
|
36
38
|
prerelease: false
|
37
39
|
version_requirements: !ruby/object:Gem::Requirement
|
38
40
|
requirements:
|
39
41
|
- - "~>"
|
40
42
|
- !ruby/object:Gem::Version
|
41
|
-
version:
|
43
|
+
version: '2'
|
42
44
|
- !ruby/object:Gem::Dependency
|
43
45
|
name: bundler
|
44
46
|
requirement: !ruby/object:Gem::Requirement
|
45
47
|
requirements:
|
46
|
-
- - "
|
48
|
+
- - ">="
|
47
49
|
- !ruby/object:Gem::Version
|
48
|
-
version: '
|
50
|
+
version: '0'
|
49
51
|
type: :development
|
50
52
|
prerelease: false
|
51
53
|
version_requirements: !ruby/object:Gem::Requirement
|
52
54
|
requirements:
|
53
|
-
- - "
|
55
|
+
- - ">="
|
54
56
|
- !ruby/object:Gem::Version
|
55
|
-
version: '
|
57
|
+
version: '0'
|
56
58
|
- !ruby/object:Gem::Dependency
|
57
59
|
name: rake
|
58
60
|
requirement: !ruby/object:Gem::Requirement
|
@@ -85,19 +87,21 @@ dependencies:
|
|
85
87
|
name: sqlite3
|
86
88
|
requirement: !ruby/object:Gem::Requirement
|
87
89
|
requirements:
|
88
|
-
- - "
|
90
|
+
- - "~>"
|
89
91
|
- !ruby/object:Gem::Version
|
90
|
-
version:
|
92
|
+
version: 1.3.6
|
91
93
|
type: :development
|
92
94
|
prerelease: false
|
93
95
|
version_requirements: !ruby/object:Gem::Requirement
|
94
96
|
requirements:
|
95
|
-
- - "
|
97
|
+
- - "~>"
|
96
98
|
- !ruby/object:Gem::Version
|
97
|
-
version:
|
99
|
+
version: 1.3.6
|
98
100
|
description: Copyable makes it easy to copy ActiveRecord models.
|
99
101
|
email:
|
100
|
-
- dchan@
|
102
|
+
- dchan@dmgroupK12.com
|
103
|
+
- ageiersbach@dmgroupK12.com
|
104
|
+
- pmorse@dmgroupK12.com
|
101
105
|
executables: []
|
102
106
|
extensions: []
|
103
107
|
extra_rdoc_files: []
|
@@ -158,7 +162,7 @@ homepage: https://github.com/dmcouncil/copyable
|
|
158
162
|
licenses:
|
159
163
|
- MIT
|
160
164
|
metadata: {}
|
161
|
-
post_install_message:
|
165
|
+
post_install_message:
|
162
166
|
rdoc_options: []
|
163
167
|
require_paths:
|
164
168
|
- lib
|
@@ -173,9 +177,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
173
177
|
- !ruby/object:Gem::Version
|
174
178
|
version: '0'
|
175
179
|
requirements: []
|
176
|
-
|
177
|
-
|
178
|
-
signing_key:
|
180
|
+
rubygems_version: 3.1.4
|
181
|
+
signing_key:
|
179
182
|
specification_version: 4
|
180
183
|
summary: ActiveRecord copier
|
181
184
|
test_files:
|