forked from openminds/deep_cloning
-
Notifications
You must be signed in to change notification settings - Fork 2
/
deep_cloning.rb
59 lines (54 loc) · 1.97 KB
/
deep_cloning.rb
1
2
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
# DeepCloning
module DeepCloning
def self.included(base) #:nodoc:
base.alias_method_chain :dup, :deep_cloning
end
# clones an ActiveRecord model.
# if passed the :include option, it will deep clone the given associations
# if passed the :except option, it won't clone the given attributes
#
# === Usage:
#
# ==== Cloning a model without an attribute
# pirate.clone :except => :name
#
# ==== Cloning a model without multiple attributes
# pirate.clone :except => [:name, :nick_name]
# ==== Cloning one single association
# pirate.clone :include => :mateys
#
# ==== Cloning multiple associations
# pirate.clone :include => [:mateys, :treasures]
#
# ==== Cloning really deep
# pirate.clone :include => {:treasures => :gold_pieces}
#
# ==== Cloning really deep with multiple associations
# pirate.clone :include => [:mateys, {:treasures => :gold_pieces}]
#
def dup_with_deep_cloning options = {}
kopy = dup_without_deep_cloning()
if options[:except]
Array(options[:except]).each do |attribute|
kopy.send("#{attribute}=", self.class.column_defaults[attribute.to_s])
end
end
if options[:include]
Array(options[:include]).each do |association, deep_associations|
if (association.kind_of? Hash)
deep_associations = association[association.keys.first]
association = association.keys.first
end
opts = deep_associations.blank? ? {} : {:include => deep_associations}
cloned_object = case self.class.reflect_on_association(association).macro
when :belongs_to, :has_one
self.send(association) && self.send(association).dup(opts)
when :has_many, :has_and_belongs_to_many
self.send(association).collect { |obj| obj.dup(opts) }
end
kopy.send("#{association}=", cloned_object)
end
end
return kopy
end
end