Class: Mongoid::Association::Referenced::HasMany::Proxy
Relationships & Source Files | |
Namespace Children | |
Modules:
| |
Extension / Inclusion / Inheritance Descendants | |
Subclasses:
|
|
Super Chains via Extension / Inclusion / Inheritance | |
Class Chain:
self,
ClassMethods ,
Forwardable,
::Mongoid::Association::Many ,
Forwardable,
::Mongoid::Association::Proxy ,
Forwardable
|
|
Instance Chain:
|
|
Inherits: |
Mongoid::Association::Many
|
Defined in: | lib/mongoid/association/referenced/has_many/proxy.rb |
Overview
Transparent proxy for has_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.
Constant Summary
::Mongoid::Association::Proxy
- Inherited
Class Attribute Summary
ClassMethods
- Extended
embedded? | Returns true if the association is an embedded one. |
Class Method Summary
-
.new(base, target, association) ⇒ Proxy
constructor
Instantiate a new references_many association.
ClassMethods
- Extended
::Mongoid::Association::Proxy
- Inherited
.apply_ordering | Apply ordering to the criteria if it was defined on the association. |
.new | Sets the target and the association metadata properties. |
Instance Attribute Summary
-
#persistable? ⇒ true | false
readonly
private
Are we able to persist this association?
::Mongoid::Association::Many
- Inherited
::Mongoid::Association::Proxy
- Inherited
#_association, | |
#_base | Model instance for the base of the association. |
#_target | Model instance for one to one associations, or array of model instances for one to many associations, for the target of the association. |
::Mongoid::Threaded::Lifecycle
- Included
#_assigning | Begin the assignment of attributes. |
#_assigning? | Is the current thread in assigning mode? |
#_binding | Execute a block in binding mode. |
#_binding? | Is the current thread in binding mode? |
#_building | Execute a block in building mode. |
#_building? | Is the current thread in building mode? |
#_creating? | Is the current thread in creating mode? |
#_loading | Execute a block in loading mode. |
#_loading? | Is the current thread in loading mode? |
Instance Method Summary
-
#<<(*args) ⇒ Array<Document>
(also: #push)
Appends a document or array of documents to the association.
-
#build(attributes = {}, type = nil) ⇒ Document
(also: #new)
Build a new document from the attributes and append it to this association without saving.
-
#clear
Alias for #purge.
-
#concat(documents) ⇒ Array<Document>
Appends an array of documents to the association.
-
#delete(document) ⇒ Document
(also: #delete_one)
Delete the document from the association.
-
#delete_all(conditions = nil) ⇒ Integer
Deletes all related documents from the database given the supplied conditions.
-
#delete_one(document)
Alias for #delete.
-
#destroy_all(conditions = nil) ⇒ Integer
Destroys all related documents from the database given the supplied conditions.
-
#each(&block) ⇒ Array<Document>
Iterate over each document in the association and yield to the provided block.
-
#exists?(id_or_conditions = :none) ⇒ true | false
Determine if any documents in this association exist in the database.
-
#find(*args) {|Object| ... } ⇒ Document | Array<Document> | nil
Find the matching document on the association, either based on id or conditions.
-
#new(attributes = {}, type = nil)
Alias for #build.
-
#nullify
(also: #nullify_all)
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.
-
#nullify_all
Alias for #nullify.
-
#purge ⇒ Many
(also: #clear)
Clear the association.
-
#push(*args)
Alias for #<<.
-
#substitute(replacement) ⇒ Many
Substitutes the supplied target documents for the existing documents in the association.
-
#unscoped ⇒ Criteria
Get a criteria for the documents without the default scoping applied.
-
#already_related?(document) ⇒ true | false
private
Whether the document and the base already have a persisted association.
-
#append(document)
private
Appends the document to the target array, updating the index on the document at the same time.
-
#binding ⇒ Binding
private
Instantiate the binding associated with this association.
-
#cascade!(document) ⇒ true | false
private
Perform the necessary cascade operations for documents that just got deleted or nullified.
-
#collection ⇒ Collection
private
Get the collection of the association in question.
-
#criteria ⇒ Criteria
private
Returns the criteria object for the target class with its documents set to target.
-
#method_missing ⇒ Criteria | Object
private
If the target array does not respond to the supplied method then try to find a named scope or criteria on the class and send the call there.
-
#persist_delayed(docs, inserts)
private
Internal use only
Internal use only
Persist all the delayed batch inserts.
-
#remove_all(conditions = nil, method = :delete_all) ⇒ Integer
private
Deletes all related documents from the database given the supplied conditions.
-
#remove_not_in(ids)
private
Remove all the documents in the proxy that do not have the provided ids.
-
#save_or_delay(doc, docs, inserts)
private
Internal use only
Internal use only
Save a persisted document immediately or delay a new document for batch insert.
-
#update_or_delete_all(removed)
private
If the association is destructive, the matching documents will be removed.
-
#with_add_callbacks(document, already_related)
private
Execute before/after add callbacks around the block unless the objects already have a persisted association.
::Mongoid::Association::Many
- Inherited
#cache_version | For compatibility with Rails’ caching. |
#create | Creates a new document on the references many association. |
#create! | Creates a new document on the references many association. |
#find_or_create_by | Find the first document given the conditions, or creates a new document with the conditions that were supplied. |
#find_or_create_by! | Find the first document given the conditions, or creates a new document with the conditions that were supplied. |
#find_or_initialize_by | Find the first |
#respond_to? | Since method_missing is overridden we should override this as well. |
#scoped | This is public access to the association’s criteria. |
#serializable_hash | Gets the document as a serializable hash, used by ActiveModel’s JSON and XML serializers. |
#unscoped | Get a criteria for the embedded documents without the default scoping applied. |
#_session, | |
#analyze_loaded_target | Return a 2-tuple of the number of elements in the relation, and the largest timestamp value. |
#analyze_unloaded_target | Returns a 2-tuple of the number of elements in the relation, and the largest timestamp value. |
#compute_cache_version | Computes the cache version for the relation using the given timestamp colum; see |
#find_or | Find the first object given the supplied attributes or create/initialize it. |
::Mongoid::Association::Proxy
- Inherited
#extend_proxies | Allow extension to be an array and extend each module. |
#extend_proxy, | |
#klass | Get the class from the association, or return nil if no association present. |
#reset_unloaded | Resets the criteria inside the association proxy. |
#substitutable | The default substitutable object for an association proxy is the clone of the target. |
::Mongoid::Association::Marshalable
- Included
#marshal_dump | Provides the data needed to Marshal.dump an association proxy. |
#marshal_load | Takes the provided data and sets it back on the proxy. |
Constructor Details
.new(base, target, association) ⇒ Proxy
Instantiate a new references_many association. Will set the foreign key and the base on the inverse object.
# File 'lib/mongoid/association/referenced/has_many/proxy.rb', line 51
def initialize(base, target, association) enum = HasMany::Enumerable.new(target, base, association) super(base, enum, association) do raise_mixed if klass. && !klass.cyclic? end end
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing ⇒ Criteria | Object
(private)
If the target array does not respond to the supplied method then try to find a named scope or criteria on the class and send the call there.
If the method exists on the array, use the default proxy behavior.
TODO: make sure we are consistingly using respond_to_missing
anywhere we define method_missing.
Instance Attribute Details
#persistable? ⇒ true
| false
(readonly, private)
Are we able to persist this association?
# File 'lib/mongoid/association/referenced/has_many/proxy.rb', line 505
def persistable? !_binding? && (_creating? || (_base.persisted? && !_building?)) 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.
# File 'lib/mongoid/association/referenced/has_many/proxy.rb', line 73
def <<(*args) docs = args.flatten return concat(docs) if docs.size > 1 if (doc = docs.first) append(doc) doc.save if persistable? && !_assigning? && !doc.validated? end self end
#append(document) (private)
Appends the document to the target array, updating the index on the document at the same time.
# File 'lib/mongoid/association/referenced/has_many/proxy.rb', line 362
def append(document) with_add_callbacks(document, (document)) do _target.push(document) characterize_one(document) bind_one(document) end end
#binding ⇒ Binding (private)
Instantiate the binding associated with this association.
#build(attributes = {}, type = nil) ⇒ Document Also known as: #new
Build a new document from the attributes and append it to this association without saving.
# File 'lib/mongoid/association/referenced/has_many/proxy.rb', line 118
def build(attributes = {}, type = nil) Factory.execute_build(type || klass, attributes, execute_callbacks: false).tap do |doc| append(doc) doc.apply_post_processed_defaults yield doc if block_given? doc.run_pending_callbacks doc.run_callbacks(:build) { doc } end end
#cascade!(document) ⇒ true
| false
(private)
Perform the necessary cascade operations for documents that just got deleted or nullified.
# File 'lib/mongoid/association/referenced/has_many/proxy.rb', line 441
def cascade!(document) return unless persistable? case _association.dependent when :delete_all document.delete when :destroy document.destroy else document.save end end
#clear
Alias for #purge.
# File 'lib/mongoid/association/referenced/has_many/proxy.rb', line 315
alias clear purge
#collection ⇒ Collection
(private)
Get the collection of the association in question.
# File 'lib/mongoid/association/referenced/has_many/proxy.rb', line 417
def collection klass.collection 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.
# File 'lib/mongoid/association/referenced/has_many/proxy.rb', line 95
def concat(documents) docs, inserts = [], [] documents.each do |doc| next unless doc append(doc) save_or_delay(doc, docs, inserts) if persistable? end persist_delayed(docs, inserts) self end
#criteria ⇒ Criteria (private)
Returns the criteria object for the target class with its documents set to target.
# File 'lib/mongoid/association/referenced/has_many/proxy.rb', line 428
def criteria @criteria ||= _association.criteria(_base) 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.
# File 'lib/mongoid/association/referenced/has_many/proxy.rb', line 140
def delete(document) execute_callbacks_around(:remove, document) do result = _target.delete(document) do |doc| if doc unbind_one(doc) cascade!(doc) unless _assigning? end end result.tap { reset_unloaded } end end
#delete_all(conditions = nil) ⇒ Integer
Deletes all related documents from the database given the supplied conditions.
# File 'lib/mongoid/association/referenced/has_many/proxy.rb', line 169
def delete_all(conditions = nil) remove_all(conditions, :delete_all) end
#delete_one(document)
Alias for #delete.
# File 'lib/mongoid/association/referenced/has_many/proxy.rb', line 155
alias delete_one delete
#destroy_all(conditions = nil) ⇒ Integer
Destroys all related documents from the database given the supplied conditions.
# File 'lib/mongoid/association/referenced/has_many/proxy.rb', line 185
def destroy_all(conditions = nil) remove_all(conditions, :destroy_all) end
#each(&block) ⇒ Array<Document>
This will load the entire association into memory.
Iterate over each document in the association and yield to the provided block.
# File 'lib/mongoid/association/referenced/has_many/proxy.rb', line 200
def each(&block) if block _target.each(&block) else to_enum end end
#exists?(id_or_conditions = :none) ⇒ true
| false
Determine if any documents in this association exist in the database.
If the association contains documents but all of the documents exist only in the application, i.e. have not been persisted to the database, this method returns false.
This method queries the database on each invocation even if the association is already loaded into memory.
# File 'lib/mongoid/association/referenced/has_many/proxy.rb', line 230
def exists?(id_or_conditions = :none) criteria.exists?(id_or_conditions) end
#find(*args) {|Object| ... } ⇒ Document | Array<Document> | nil
Each argument can be an individual id, an array of ids or a nested array. Each array will be flattened.
This will keep matching documents in memory for iteration later.
Find the matching document on the association, either based on id or conditions.
This method delegates to Criteria#find. If this method is not given a block, it returns one or many documents for the provided _id values.
If this method is given a block, it returns the first document of those found by the current ::Mongoid::Criteria
object for which the block returns a truthy value.
#new(attributes = {}, type = nil)
Alias for #build.
# File 'lib/mongoid/association/referenced/has_many/proxy.rb', line 128
alias new build
#nullify Also known as: #nullify_all
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.
# File 'lib/mongoid/association/referenced/has_many/proxy.rb', line 277
def nullify criteria.update_all(foreign_key => nil) _target.clear do |doc| unbind_one(doc) doc.changed_attributes.delete(foreign_key) end end
#nullify_all
Alias for #nullify.
# File 'lib/mongoid/association/referenced/has_many/proxy.rb', line 285
alias nullify_all nullify
#persist_delayed(docs, inserts) (private)
Persist all the delayed batch inserts.
# File 'lib/mongoid/association/referenced/has_many/proxy.rb', line 488
def persist_delayed(docs, inserts) return if docs.empty? collection.insert_many(inserts, session: _session) docs.each do |doc| doc.new_record = false doc.run_after_callbacks(:create, :save) unless _association.autosave? doc.post_persist end end
#purge ⇒ Many Also known as: #clear
Clear the association. Will delete the documents from the db if they are already persisted.
# File 'lib/mongoid/association/referenced/has_many/proxy.rb', line 294
def purge return nullify unless _association.destructive? after_remove_error = nil criteria.delete_all many = _target.clear do |doc| execute_callback :before_remove, doc unbind_one(doc) doc.destroyed = true begin execute_callback :after_remove, doc rescue StandardError => e after_remove_error = e end end raise after_remove_error if after_remove_error many end
#push(*args)
Alias for #<<.
# File 'lib/mongoid/association/referenced/has_many/proxy.rb', line 84
alias push <<
#remove_all(conditions = nil, method = :delete_all) ⇒ Integer (private)
Deletes all related documents from the database given the supplied conditions.
# File 'lib/mongoid/association/referenced/has_many/proxy.rb', line 522
def remove_all(conditions = nil, method = :delete_all) selector = conditions || {} removed = klass.send(method, selector.merge!(criteria.selector)) _target.delete_if do |doc| doc._matches?(selector).tap do |b| unbind_one(doc) if b end end removed end
#remove_not_in(ids) (private)
Remove all the documents in the proxy that do not have the provided ids.
# File 'lib/mongoid/association/referenced/has_many/proxy.rb', line 540
def remove_not_in(ids) removed = criteria.not_in(_id: ids) update_or_delete_all(removed) in_memory.each do |doc| next if ids.include?(doc._id) unbind_one(doc) _target.delete(doc) doc.destroyed = true if _association.destructive? end end
#save_or_delay(doc, docs, inserts) (private)
Save a persisted document immediately or delay a new document for batch insert.
#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.
# File 'lib/mongoid/association/referenced/has_many/proxy.rb', line 327
def substitute(replacement) if replacement new_docs, docs = replacement.compact, [] new_ids = new_docs.map(&:_id) remove_not_in(new_ids) new_docs.each do |doc| docs.push(doc) if doc.send(foreign_key) != _base.send(_association.primary_key) end concat(docs) else purge end self end
#unscoped ⇒ Criteria
Get a criteria for the documents without the default scoping applied.
# File 'lib/mongoid/association/referenced/has_many/proxy.rb', line 349
def unscoped klass.unscoped.where(foreign_key => _base.send(_association.primary_key)) end
#update_or_delete_all(removed) (private)
If the association is destructive, the matching documents will be removed. Otherwise, their foreign keys will be set to nil.
# File 'lib/mongoid/association/referenced/has_many/proxy.rb', line 559
def update_or_delete_all(removed) if _association.destructive? removed.delete_all else removed.update_all(foreign_key => nil) end end
#with_add_callbacks(document, already_related) (private)
Execute before/after add callbacks around the block unless the objects already have a persisted association.
# File 'lib/mongoid/association/referenced/has_many/proxy.rb', line 379
def with_add_callbacks(document, ) execute_callback :before_add, document unless yield execute_callback :after_add, document unless end