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

Inherits:
Mongoid::Association::Referenced::HasMany::Proxy show all
Extended by:
ClassMethods
Defined in:
lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb

Overview

Transparent proxy for has_and_belongs_to_many associations. An instance of this class is returned when calling the association getter method on the subject document. This class inherits from Mongoid::Association::Proxy and forwards most of its methods to the target of the association, i.e. the array of documents on the opposite-side collection which must be loaded.

Defined Under Namespace

Modules: ClassMethods

Constant Summary

Constants inherited from Proxy

Proxy::KEEPER_METHODS

Instance Attribute Summary

Attributes inherited from Proxy

#_association, #_base, #_target

Instance Method Summary collapse

Methods included from ClassMethods

eager_loader, embedded?

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

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

Methods included from Mongoid::Association::Referenced::HasMany::Proxy::ClassMethods

#eager_loader, #embedded?

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, #initialize, #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

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.

rubocop:disable Metrics/AbcSize

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.



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

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))
        doc.save if child_persistable?(doc)
        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:



123
124
125
126
127
128
129
130
131
132
# File 'lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb', line 123

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:



105
106
107
108
109
110
111
# File 'lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb', line 105

def concat(documents)
  ids, docs, inserts = {}, [], []
  documents.each { |doc| append_document(doc, ids, docs, inserts) }
  _base.push(foreign_key => ids.keys) if persistable? || _creating?
  persist_delayed(docs, inserts)
  self
end

#delete(document) ⇒ Document Also known as: delete_one

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:



146
147
148
149
150
151
152
153
154
# File 'lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb', line 146

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.



168
169
170
171
172
173
# File 'lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb', line 168

def nullify(replacement = [])
  _target.each { |doc| execute_callback :before_remove, doc }
  cleanup_inverse_for(replacement) unless _association.forced_nil_inverse?
  _base.set(foreign_key => _base.public_send(foreign_key).clear) if persistable?
  clear_target_for_nullify
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.



189
190
191
192
193
194
195
196
197
198
# File 'lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb', line 189

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

#unscopedCriteria

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

Examples:

Get the unscoped criteria.

person.preferences.unscoped

Returns:



207
208
209
# File 'lib/mongoid/association/referenced/has_and_belongs_to_many/proxy.rb', line 207

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