Module: SourceIds::ClassMethods

Defined in:
lib/source_ids.rb

Instance Method Summary collapse

Instance Method Details

#accepts_source_ids_for(source_association_name, options = {}) ⇒ Object



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
# 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
  fk_in_relation = source_association.source_reflection.foreign_key
  source_ids_name = options[:as] || "#{source_association_name.to_s.singularize}_ids"

  # _source_ids=
  define_method "_#{source_ids_name}=" do |ids|
    ids = ids.find_all(&:present?) # care for hidden field of collection_select

    # mark destruction if not included in ids
    send(relation.name).each do |r|
      source_id = r.send(fk_in_relation)
      r.mark_for_destruction unless ids.include?(source_id)
    end

    ids.each do |source_id|
      unless send(relation.name).detect{|r| r.send(fk_in_relation) == 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)) <=> ids.index(b.send(fk_in_relation))
      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
end