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
|
# File 'lib/source_ids.rb', line 9
def accepts_source_ids_for(source_association_name, options = {})
source_association = reflect_on_association(source_association_name)
raise "Could not find association #{source_association_name}" unless source_association
relation = source_association.through_reflection
raise "#{source_association_name} does not have :through" unless relation
source_name = source_association.source_reflection.name
fk_in_relation = source_association.source_reflection.foreign_key
source_ids_name = options[:as] || "#{source_association_name.to_s.singularize}_ids"
define_method "_#{source_ids_name}=" do |ids|
ids = ids.find_all(&:present?).map(&:to_s)
removed = send(relation.name).find_all{|r| !ids.include?(r.send(fk_in_relation).to_s) }
removed.each do |r|
if r.new_record?
send(relation.name).delete(r)
else
r.mark_for_destruction
end
end
ids.each do |source_id|
unless send(relation.name).detect{|r| r.send(fk_in_relation).to_s == source_id}
send(relation.name).build(fk_in_relation => source_id)
end
end
send(relation.name).target.sort! do |a, b|
if a.marked_for_destruction? && b.marked_for_destruction?
0
elsif a.marked_for_destruction?
-1
elsif b.marked_for_destruction?
1
else
ids.index(a.send(fk_in_relation).to_s) <=> ids.index(b.send(fk_in_relation).to_s)
end
end
end
define_method "_#{source_ids_name}" do
send(relation.name).find_all{|r| !r.marked_for_destruction?}.map(&fk_in_relation.to_sym)
end
define_method "_#{source_association_name}" do
send(relation.name).find_all{|r| !r.marked_for_destruction?}.map(&source_name)
end
end
|