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
|
# File 'lib/acts_as_inheritable.rb', line 5
def acts_as_inheritable(options)
fail ArgumentError, "Hash expected, got #{options.class.name}" unless options.is_a?(Hash)
fail ArgumentError, 'Empty options' if options[:attributes].blank? && options[:associations].blank?
class_attribute :inheritable_configuration
self.inheritable_configuration = {}
self.inheritable_configuration.merge!(options)
class_eval do
def has_parent?
parent.present?
end
def inherit_relations(model_parent = send(:parent), current = self)
if model_parent && current.class.method_defined?(:inheritable_configuration) && current.class.inheritable_configuration[:associations]
current.class.inheritable_configuration[:associations].each do |relation|
parent_relation = model_parent.send(relation)
relation_instances = parent_relation.respond_to?(:each) ? parent_relation : [parent_relation].compact
relation_instances.each do |relation_instance|
inherit_instance(current, model_parent, relation, relation_instance)
end
end
end
end
def inherit_instance(current, model_parent, relation, relation_instance)
new_relation = relation_instance.dup
belongs_to_associations_names = model_parent.class.reflect_on_all_associations(:belongs_to).collect(&:name)
saved =
if belongs_to_associations_names.include?(relation.to_sym)
new_relation = relation_instance.duplicate! if relation_instance.respond_to?(:duplicate!)
current.send("#{relation}=", new_relation)
current.save
else
parent_name = verify_parent_name(new_relation, model_parent)
new_relation.send("#{parent_name}=", current)
new_relation.save
end
inherit_relations(relation_instance, new_relation) if saved
end
def verify_parent_name(new_relation, model_parent)
parent_name = model_parent.class.to_s.downcase
return parent_name if new_relation.respond_to?(parent_name)
many_and_one_associations = model_parent.class.reflect_on_all_associations.select { |a| a.macro != :belongs_to }
many_and_one_associations.each do |association|
next unless association.klass.to_s.downcase == new_relation.class.to_s.downcase && association.options.key?(:as)
as = association.options[:as].to_s
if new_relation.respond_to?(as) && !new_relation.respond_to?(parent_name)
parent_name = as
break
end
end
unless new_relation.respond_to?(parent_name)
new_relation.class.reflections.each_key do |reflection|
next unless new_relation.class.reflections[reflection].class_name == model_parent.class.name
parent_name = reflection
break
end
end
parent_name
end
def inherit_attributes(force = false, not_force_for = [], method_to_update = nil)
available_methods = ['update_attributes', 'update_columns']
if has_parent? && self.class.inheritable_configuration[:attributes]
self.class.inheritable_configuration[:attributes].each do |attribute|
current_val = send(attribute)
if (force && !not_force_for.include?(attribute)) || current_val.blank?
if method_to_update && available_methods.include?(method_to_update)
send(method_to_update, {attribute => parent.send(attribute)})
else
send("#{attribute}=", parent.send(attribute))
end
end
end
end
end
end
end
|