Class: Mongoid::Association::Referenced::HasAndBelongsToMany::Proxy

Inherits:
Mongoid::Association::Referenced::HasMany::Proxy show all
Defined in:
build/mongoid-master/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb

Overview

This class defines the behavior for all associations that are a many-to-many between documents in different collections.

Instance Attribute Summary

Attributes inherited from Proxy

#_association, #_base, #_target

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Mongoid::Association::Referenced::HasMany::Proxy

#delete_all, #destroy_all, #each, #exists?, #find, #initialize

Methods inherited from Many

#blank?, #create, #create!, #find_or_create_by, #find_or_create_by!, #find_or_initialize_by, #nil?, #respond_to?, #scoped, #serializable_hash

Methods inherited from Proxy

apply_ordering, #extend_proxies, #init, #klass, #reset_unloaded, #substitutable

Methods included from Marshalable

#marshal_dump, #marshal_load

Constructor Details

This class inherits a constructor from Mongoid::Association::Referenced::HasMany::Proxy

Dynamic Method Handling

This class handles dynamic methods through the method_missing method in the class Mongoid::Association::Referenced::HasMany::Proxy

Class Method Details

.eager_loader(association, docs) ⇒ Object

Get the Eager object for this type of association.

Examples:

Get the eager loader object

Parameters:

  • association (Association)

    The association object.

  • docs (Array<Document>)

    The array of documents.



326
327
328
# File 'build/mongoid-master/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb', line 326

def eager_loader(association, docs)
  Eager.new(association, docs)
end

.embedded?false

Returns true if the association is an embedded one. In this case always false.

Examples:

Is this association embedded?

Referenced::ManyToMany.embedded?

Returns:

  • (false)

    Always false.



337
338
339
# File 'build/mongoid-master/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb', line 337

def embedded?
  false
end

Instance Method Details

#<<(*args) ⇒ Array<Document> Also known as: push

Appends a document or array of documents to the association. Will set the parent and update the index in the process.

Examples:

Append a document.

person.posts << post

Push a document.

person.posts.push(post)

Concat with other documents.

person.posts.concat([ post_one, post_two ])

Parameters:

  • *args (Document...)

    Any number of documents.

Returns:

  • (Array<Document>)

    The loaded docs.



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
# File 'build/mongoid-master/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb', line 27

def <<(*args)
  docs = args.flatten
  return concat(docs) if docs.size > 1
  if doc = docs.first
    append(doc) do
      # We ignore the changes to the value for the foreign key in the
      # changed_attributes hash in this block of code for two reasons:
      #
      # 1) The add_to_set method deletes the value for the foreign
      #    key in the changed_attributes hash, but if we enter this
      #    method with a value for the foreign key in the
      #    changed_attributes hash, then we want it to exist outside
      #    this method as well. It's used later on in the Syncable
      #    module to set the inverse foreign keys.
      # 2) The reset_unloaded method accesses the value for the foreign
      #    key on _base, which causes it to get added to the
      #    changed_attributes hash. This happens because when reading
      #    a "resizable" attribute, it is automatically added to the
      #    changed_attributes hash. This is true only for the foreign
      #    key value for HABTM associations as the other associations
      #    use strings for their foreign key values. For consistency
      #    with the other associations, we ignore this addition to
      #    the changed_attributes hash.
      #    See MONGOID-4843 for a longer discussion about this.
      reset_foreign_key_changes do
        _base.add_to_set(foreign_key => doc.public_send(_association.primary_key))

        if child_persistable?(doc)
          doc.save
        end
        reset_unloaded
      end
    end
  end
  unsynced(_base, foreign_key) and self
end

#build(attributes = {}, type = nil) {|doc| ... } ⇒ Document Also known as: new

Build a new document from the attributes and append it to this association without saving.

Examples:

Build a new document on the association.

person.posts.build(:title => "A new post")

Parameters:

  • attributes (Hash) (defaults to: {})

    The attributes of the new document.

  • type (Class) (defaults to: nil)

    The optional subclass to build.

Yields:

  • (doc)

Returns:



107
108
109
110
111
112
113
114
115
116
# File 'build/mongoid-master/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb', line 107

def build(attributes = {}, type = nil)
  doc = Factory.execute_build(type || klass, attributes, execute_callbacks: false)
  append(doc)
  doc.apply_post_processed_defaults
  _base.public_send(foreign_key).push(doc.public_send(_association.primary_key))
  unsynced(doc, inverse_foreign_key)
  yield(doc) if block_given?
  doc.run_pending_callbacks
  doc
end

#concat(documents) ⇒ Array<Document>

Appends an array of documents to the association. Performs a batch insert of the documents instead of persisting one at a time.

Examples:

Concat with other documents.

person.posts.concat([ post_one, post_two ])

Parameters:

  • documents (Array<Document>)

    The docs to add.

Returns:



75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'build/mongoid-master/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb', line 75

def concat(documents)
  ids, docs, inserts = {}, [], []
  documents.each do |doc|
    next unless doc
    append(doc)
    if persistable? || _creating?
      ids[doc.public_send(_association.primary_key)] = true
      save_or_delay(doc, docs, inserts)
    else
      existing = _base.public_send(foreign_key)
      unless existing.include?(doc.public_send(_association.primary_key))
        existing.push(doc.public_send(_association.primary_key)) and unsynced(_base, foreign_key)
      end
    end
  end
  if persistable? || _creating?
    _base.push(foreign_key => ids.keys)
  end
  persist_delayed(docs, inserts)
  self
end

#delete(document) ⇒ Document

Delete the document from the association. This will set the foreign key on the document to nil. If the dependent options on the association are :delete_all or :destroy the appropriate removal will occur.

Examples:

Delete the document.

person.posts.delete(post)

Parameters:

  • document (Document)

    The document to remove.

Returns:



130
131
132
133
134
135
136
137
138
# File 'build/mongoid-master/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb', line 130

def delete(document)
  doc = super
  if doc && persistable?
    _base.pull(foreign_key => doc.public_send(_association.primary_key))
    _target._unloaded = criteria
    unsynced(_base, foreign_key)
  end
  doc
end

#nullify(replacement = []) ⇒ Object Also known as: nullify_all, clear, purge

Removes all associations between the base document and the target documents by deleting the foreign keys and the references, orphaning the target documents in the process.

Examples:

Nullify the association.

person.preferences.nullify

Parameters:

  • replacement (Array<Document>) (defaults to: [])

    The replacement documents.



148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'build/mongoid-master/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb', line 148

def nullify(replacement = [])
  _target.each do |doc|
    execute_callback :before_remove, doc
  end
  unless _association.forced_nil_inverse?
    if field = _association.options[:inverse_primary_key]
      ipk = _base.public_send(field)
    else
      ipk = _base._id
    end
    if replacement
      objects_to_clear = _base.public_send(foreign_key) - replacement.collect do |object|
        object.public_send(_association.primary_key)
      end
      criteria(objects_to_clear).pull(inverse_foreign_key => ipk)
    else
      criteria.pull(inverse_foreign_key => ipk)
    end
  end
  if persistable?
    _base.set(foreign_key => _base.public_send(foreign_key).clear)
  end
  after_remove_error = nil
  many_to_many = _target.clear do |doc|
    unbind_one(doc)
    unless _association.forced_nil_inverse?
      doc.changed_attributes.delete(inverse_foreign_key)
    end
    begin
      execute_callback :after_remove, doc
    rescue => e
      after_remove_error = e
    end
  end
  raise after_remove_error if after_remove_error
  many_to_many
end

#substitute(replacement) ⇒ Many

Substitutes the supplied target documents for the existing documents in the association. If the new target is nil, perform the necessary deletion.

person.preferences.substitute([ new_post ])

Examples:

Replace the association.

Parameters:

  • replacement (Array<Document>)

    The replacement target.

Returns:

  • (Many)

    The association.



200
201
202
203
204
205
206
207
208
209
# File 'build/mongoid-master/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb', line 200

def substitute(replacement)
  purge(replacement)
  unless replacement.blank?
    push(replacement.compact.uniq)
  else
    reset_unloaded
    clear_foreign_key_changes
  end
  self
end

#unscopedCriteria

Get a criteria for the documents without the default scoping applied.

Examples:

Get the unscoped criteria.

person.preferences.unscoped

Returns:



218
219
220
# File 'build/mongoid-master/lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb', line 218

def unscoped
  klass.unscoped.any_in(_id: _base.public_send(foreign_key))
end