3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
|
# File 'lib/clone_util.rb', line 3
def self.deep_clone_options(options={})
class_eval do
@clone_options = options
def self.allow_dup
@clone_options[:allow_dup]
end
def self.clone_info
@clone_options
end
def self.clone_associations
@clone_options[:associations]
end
def self.equivalent_associations
@clone_options[:equivalent_associations]
end
def self.unequal_attrs
unequal_attrs = ['id']
unequal_attrs.concat(@clone_options[:unequal_attributes]) if @clone_options[:unequal_attributes]
unequal_attrs
end
def self.ignore_attributes
ignore_attributes = ['created_at', 'updated_at', 'created_by_id', 'updated_by_id']
ignore_attributes << @clone_options[:parent_id_attr].first if @clone_options[:parent_id_attr]
ignore_attributes
end
def self.parent_id_attr
@clone_options[:parent_id_attr]
end
def deep_clone
recursive_clone
end
def recursive_clone(parent_object_id = nil,
clone_id_hash = {} )
self.transaction do
cloned_object = dup
unequal_attrs = self.class.clone_info[:unequal_attributes] || []
unequal_attrs.each do |a|
cloned_object.send("#{a.to_s}=", nil)
end
if self.class.parent_id_attr and parent_object_id
cloned_object.send("#{self.class.parent_id_attr[0].to_s}=", parent_object_id)
end
begin
obj_attrs = cloned_object.attributes.clone
self.class.ignore_attributes.each { |a| obj_attrs.delete(a.to_s)}
if self.class.parent_id_attr and parent_object_id
obj_attrs["#{self.class.parent_id_attr[0].to_s}"] = parent_object_id
end
cloned_object.save!
clone_id_hash["#{self.class.table_name}_#{self.id}"] = cloned_object.id
rescue Exception => e
logger.info("deepclone: Clone save failed for " + cloned_object.inspect)
raise e
end
add_cloned_associations(cloned_object, clone_id_hash)
add_equivalent_associations(cloned_object, clone_id_hash)
clone_id_hash["#{self.class.table_name}_#{self.id}"] = cloned_object.id
cloned_object
end
end
def add_equivalent_associations(cloned_object, clone_id_hash)
if self.class.equivalent_associations
self.class.equivalent_associations.each do |association|
assocn = self.class.reflect_on_association(association)
assocn_table_name = eval(assocn.class_name).table_name
assocn_id = send(assocn.foreign_key)
if assocn_id and (equivalent_id = clone_id_hash["#{assocn_table_name}_#{assocn_id}"])
cloned_object.send("#{assocn.foreign_key}=", equivalent_id)
end
end
cloned_object.save!
end
end
def add_cloned_associations(cloned_object, clone_id_hash)
if self.class.clone_associations
self.class.clone_associations.each do |association|
assocn = self.class.reflect_on_association(association)
if assocn.macro == :has_many
send(association).each do |obj|
c_obj = obj.respond_to?('deep_clone') ? obj.recursive_clone(cloned_object.id, clone_id_hash) : obj.dup
cloned_object.send(association) << c_obj unless c_obj.nil?
end
elsif assocn.macro == :has_and_belongs_to_many
cloned_object.send("#{association.to_s}=", send(association))
elsif (assocn.macro == :belongs_to) or (assocn.macro == :has_one)
source_obj = send(association)
unless source_obj.nil?
c_obj = source_obj.respond_to?('deep_clone') ? source_obj.recursive_clone(cloned_object.id, clone_id_hash) : source_obj.dup
cloned_object.send("#{association.to_s}=", c_obj) unless c_obj.nil?
end
end
end
end
end
end
end
|