Module: Mongoid::Persistable::Updatable
| Relationships & Source Files | |
| Extension / Inclusion / Inheritance Descendants | |
|
Included In:
| |
| Defined in: | lib/mongoid/persistable/updatable.rb |
Overview
Defines behavior for persistence operations that update existing documents.
Instance Method Summary
-
#update(attributes = {}) ⇒ true | false
(also: #update_attributes)
Update the document attributes in the database.
-
#update!(attributes = {}) ⇒ true | false
(also: #update_attributes!)
Update the document attributes in the database and raise an error if validation failed.
-
#update_attribute(name, value) ⇒ true | false
Update a single attribute and persist the entire document.
-
#update_attributes(attributes = {})
Alias for #update.
-
#update_attributes!(attributes = {})
Alias for #update!.
-
#enforce_immutability_of_id_field!
private
Checks to see if the _id field has been modified.
-
#init_atomic_updates ⇒ Array<Hash>
private
Internal use only
Internal use only
Initialize the atomic updates.
-
#prepare_update(options = {}) ⇒ true | false
private
Internal use only
Internal use only
Prepare the update for execution.
-
#process_touch_option(options, children, &block)
private
If there is a touch option and it is false, this method will call the timeless method so that the updated_at attribute is not updated.
-
#run_all_callbacks_for_update(update_children, &block)
private
Consolidates all the callback invocations into a single place, to avoid cluttering the logic in #prepare_update.
-
#update_document(options = {}) ⇒ true | false
private
Update the document in the database.
Instance Method Details
#enforce_immutability_of_id_field! (private)
Checks to see if the _id field has been modified. If it has, and if the document has already been persisted, this is an error. Otherwise, returns without side-effects.
Note that if Mongoid::Config.immutable_ids is false, this will do nothing.
# File 'lib/mongoid/persistable/updatable.rb', line 193
def enforce_immutability_of_id_field! # special case here: we *do* allow the _id to be mutated if it was # previously nil. This addresses an odd case exposed in # has_one/proxy_spec.rb where `person.create_address` would # (somehow?) create the address with a nil _id first, before then # saving it *again* with the correct _id. return unless _id_changed? && !_id_was.nil? && persisted? raise Errors::ImmutableAttribute.new(:_id, _id) if Mongoid::Config.immutable_ids Mongoid::Warnings.warn_mutable_ids end
#init_atomic_updates ⇒ Array<Hash> (private)
Initialize the atomic updates.
# File 'lib/mongoid/persistable/updatable.rb', line 75
def init_atomic_updates updates = atomic_updates conflicts = updates.delete(:conflicts) || {} [ updates, conflicts ] end
#prepare_update(options = {}) ⇒ true | false (private)
Prepare the update for execution. Validates and runs callbacks, etc.
# File 'lib/mongoid/persistable/updatable.rb', line 96
def prepare_update( = {}) raise Errors::ReadonlyDocument.new(self.class) if readonly? && !Mongoid.legacy_readonly enforce_immutability_of_id_field! ensure_client_compatibility! return false if performing_validations?() && invalid?([:context] || :update) process_flagged_destroys update_children = cascadable_children(:update) process_touch_option(, update_children) do run_all_callbacks_for_update(update_children) do result = yield(self) self.previously_new_record = false post_process_persist(result, ) true end end end
#process_touch_option(options, children, &block) (private)
If there is a touch option and it is false, this method will call the timeless method so that the updated_at attribute is not updated. It will call the timeless method on all of the cascadable children as well. Note that timeless is cleared in the before_update callback.
# File 'lib/mongoid/persistable/updatable.rb', line 174
def process_touch_option(, children, &block) if .fetch(:touch, true) yield else timeless children.each(&:timeless) suppress_touch_callbacks(&block) end end
#run_all_callbacks_for_update(update_children, &block) (private)
Consolidates all the callback invocations into a single place, to avoid cluttering the logic in #prepare_update.
# File 'lib/mongoid/persistable/updatable.rb', line 211
def run_all_callbacks_for_update(update_children, &block) run_callbacks(:commit, with_children: true, skip_if: -> { in_transaction? }) do run_callbacks(:save, with_children: false) do run_callbacks(:update, with_children: false) do run_callbacks(:persist_parent, with_children: false) do _mongoid_run_child_callbacks(:save) do _mongoid_run_child_callbacks(:update, children: update_children, &block) # _mongoid_run_child_callbacks :update end # _mongoid_run_child_callbacks :save end # :persist_parent end # :update end # :save end # :commit end
#update(attributes = {}) ⇒ true | false
Also known as: #update_attributes
Update the document attributes in the database.
# File 'lib/mongoid/persistable/updatable.rb', line 37
def update(attributes = {}) assign_attributes(attributes) save end
#update!(attributes = {}) ⇒ true | false
Also known as: #update_attributes!
Update the document attributes in the database and raise an error if validation failed.
# File 'lib/mongoid/persistable/updatable.rb', line 55
def update!(attributes = {}) result = update_attributes(attributes) unless result fail_due_to_validation! unless errors.empty? fail_due_to_callback!(:update_attributes!) end result end
#update_attribute(name, value) ⇒ true | false
Update a single attribute and persist the entire document. This skips validation but fires the callbacks.
# File 'lib/mongoid/persistable/updatable.rb', line 21
def update_attribute(name, value) as_writable_attribute!(name, value) do |_access| normalized = name.to_s process_attribute(normalized, value) save(validate: false) end end
#update_attributes(attributes = {})
Alias for #update.
# File 'lib/mongoid/persistable/updatable.rb', line 41
alias update_attributes update
#update_attributes!(attributes = {})
Alias for #update!.
# File 'lib/mongoid/persistable/updatable.rb', line 63
alias update_attributes! update!
#update_document(options = {}) ⇒ true | false (private)
Update the document in the database.
# File 'lib/mongoid/persistable/updatable.rb', line 126
def update_document( = {}) prepare_update() do updates, conflicts = init_atomic_updates unless updates.empty? coll = collection(_root) selector = atomic_selector # TODO: DRIVERS-716: If a new "Bulk Write" API is introduced, it may # become possible to handle the writes for conflicts in the following call. coll.find(selector).update_one(positionally(selector, updates), session: _session) # The following code applies updates which would cause # path conflicts in MongoDB, for example when changing attributes # of foo.0.bars while adding another foo. Each conflicting update # is applied using its own write. conflicts.each_pair do |modifier, changes| # Group the changes according to their root key which is # the top-level association name. # This handles at least the cases described in MONGOID-4982. conflicting_change_groups = changes.group_by do |key, _| key.split('.', 2).first end.values # Apply changes in batches. Pop one change from each # field-conflict group round-robin until all changes # have been applied. while batched_changes = conflicting_change_groups.map(&:pop).compact.to_h.presence coll.find(selector).update_one( positionally(selector, modifier => batched_changes), session: _session ) end end end end end