Class: Zermelo::Associations::HasAndBelongsToMany

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/zermelo/associations/has_and_belongs_to_many.rb

Instance Method Summary collapse

Constructor Details

#initialize(parent, name) ⇒ HasAndBelongsToMany

Returns a new instance of HasAndBelongsToMany.



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# File 'lib/zermelo/associations/has_and_belongs_to_many.rb', line 20

def initialize(parent, name)
  @parent = parent

  @backend = parent.send(:backend)

  @record_ids_key = Zermelo::Records::Key.new(
    :klass  => parent.class.send(:class_key),
    :id     => parent.id,
    :name   => "#{name}_ids",
    :type   => :set,
    :object => :association
  )

  parent.class.send(:with_association_data, name.to_sym) do |data|
    @associated_class = data.data_klass
    @lock_klasses     = [data.data_klass] + data.related_klasses
    @inverse          = data.inverse
    @callbacks        = data.callbacks
  end
end

Instance Method Details

#<<(record) ⇒ Object



41
42
43
44
# File 'lib/zermelo/associations/has_and_belongs_to_many.rb', line 41

def <<(record)
  add(record)
  self  # for << 'a' << 'b'
end

#add(*records) ⇒ Object



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/zermelo/associations/has_and_belongs_to_many.rb', line 46

def add(*records)
  raise 'No records to add' if records.empty?
  raise 'Invalid record class' unless records.all? {|r| r.is_a?(@associated_class)}
  raise "Record(s) must have been saved" unless records.all? {|r| r.persisted?}
  @parent.class.lock(*@lock_klasses) do
    ba = @callbacks[:before_add]
    if ba.nil? || !@parent.respond_to?(ba) || !@parent.send(ba, *records).is_a?(FalseClass)
      records.each do |record|
        @associated_class.send(:load, record.id).send(@inverse.to_sym).
          send(:add_without_inverse, @parent)
      end
      add_without_inverse(*records)
      aa = @callbacks[:after_add]
      @parent.send(aa, *records) if !aa.nil? && @parent.respond_to?(aa)
    end
  end
end

#delete(*records) ⇒ Object

TODO support dependent delete, for now just deletes the association



65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/zermelo/associations/has_and_belongs_to_many.rb', line 65

def delete(*records)
  raise 'No records to delete' if records.empty?
  raise 'Invalid record class' unless records.all? {|r| r.is_a?(@associated_class)}
  raise "Record(s) must have been saved" unless records.all? {|r| r.persisted?}
  @parent.class.lock(*@lock_klasses) do
    br = @callbacks[:before_remove]
    if br.nil? || !@parent.respond_to?(br) || !@parent.send(br, *records).is_a?(FalseClass)
      records.each do |record|
        @associated_class.send(:load, record.id).send(@inverse.to_sym).
          send(:delete_without_inverse, @parent)
      end
      delete_without_inverse(*records)
      ar = @callbacks[:after_remove]
      @parent.send(ar, *records) if !ar.nil? && @parent.respond_to?(ar)
    end
  end
end