Module: Mongoid::Association::Referenced::AutoSave
| Relationships & Source Files | |
| Extension / Inclusion / Inheritance Descendants | |
|
Included In:
| |
| Super Chains via Extension / Inclusion / Inheritance | |
|
Class Chain:
self,
ActiveSupport::Concern
|
|
| Defined in: | lib/mongoid/association/referenced/auto_save.rb |
Overview
Mixin module included into ::Mongoid::Document which adds the ability to automatically save opposite-side documents in referenced associations when saving the subject document.
Class Method Summary
-
.define_autosave!(association) ⇒ Class
Define the autosave method on an association’s owning class for an associated object.
Instance Attribute Summary
-
#autosaved? ⇒ true | false
readonly
Used to prevent infinite loops in associated autosaves.
Instance Method Summary
-
#__autosaving__
Begin the associated autosave.
-
#changed_for_autosave?(doc, seen = Set.new) ⇒ true | false
Check if there are changes for auto-saving.
-
#autosave_children_changed?(doc, seen) ⇒ true | false
private
Returns true if any in-memory referenced child with autosave: true needs saving.
-
#in_memory_docs(assoc_value)
private
Returns the in-memory documents for an association value without triggering a database load of any unloaded documents.
Class Method Details
.define_autosave!(association) ⇒ Class
Define the autosave method on an association’s owning class for an associated object.
# File 'lib/mongoid/association/referenced/auto_save.rb', line 62
def self.define_autosave!(association) association.inverse_class.tap do |klass| save_method = :"autosave_documents_for_#{association.name}" klass.send(:define_method, save_method) do if before_callback_halted? self.before_callback_halted = false else __autosaving__ do if assoc_value = ivar(association.name) Array(assoc_value).each do |doc| next unless changed_for_autosave?(doc) pc = doc.persistence_context? ? doc.persistence_context : persistence_context.for_child(doc) doc.with(pc) do |d| d.save end end end end end end klass.after_persist_parent save_method, unless: :autosaved? end end
Instance Attribute Details
#autosaved? ⇒ true | false (readonly)
Used to prevent infinite loops in associated autosaves.
# File 'lib/mongoid/association/referenced/auto_save.rb', line 18
def autosaved? Threaded.autosaved?(self) end
Instance Method Details
#__autosaving__
Begin the associated autosave.
# File 'lib/mongoid/association/referenced/auto_save.rb', line 26
def __autosaving__ Threaded.begin_autosave(self) yield ensure Threaded.exit_autosave(self) end
#autosave_children_changed?(doc, seen) ⇒ true | false (private)
Returns true if any in-memory referenced child with autosave: true needs saving.
# File 'lib/mongoid/association/referenced/auto_save.rb', line 96
def autosave_children_changed?(doc, seen) if Mongoid.autosave_saves_unchanged_documents? Mongoid::Warnings.warn_autosave_saves_unchanged_documents return true end doc.class.relations.values.select { |a| a.autosave? && !a. }.any? do |assoc| (assoc_value = doc.ivar(assoc.name)) && in_memory_docs(assoc_value).any? { |child| changed_for_autosave?(child, seen) } end end
#changed_for_autosave?(doc, seen = Set.new) ⇒ true | false
Check if there are changes for auto-saving. Returns true if the document is new, changed, or marked for destruction, or if any in-memory referenced child with autosave: true recursively satisfies the same condition.
The seen set prevents infinite recursion when autosave associations form a cycle (e.g. a belongs_to with autosave: true whose target has a has_many with autosave: true pointing back).
# File 'lib/mongoid/association/referenced/auto_save.rb', line 46
def changed_for_autosave?(doc, seen = Set.new) return false unless seen.add?(doc) doc.new_record? || doc.changed? || doc.marked_for_destruction? || autosave_children_changed?(doc, seen) end
#in_memory_docs(assoc_value) (private)
Returns the in-memory documents for an association value without triggering a database load of any unloaded documents. ::Mongoid::Association proxies expose in_memory for this purpose; a plain document (which belongs_to can store directly in the ivar) is itself in-memory.
# File 'lib/mongoid/association/referenced/auto_save.rb', line 112
def in_memory_docs(assoc_value) assoc_value.respond_to?(:in_memory) ? assoc_value.in_memory : [ assoc_value ] end