class Mongoid::Association::Embedded::EmbedsOne::Proxy

Transparent proxy for embeds_one associations. An instance of this class is returned when calling the association getter method on the parent document. This class inherits from Mongoid::Association::Proxy and forwards most of its methods to the target of the association, i.e. the child document.

Constants

VALID_OPTIONS

The valid options when defining this association.

@return [ Array<Symbol> ] The allowed options when defining this association.

Public Class Methods

eager_loader(associations, docs) click to toggle source

Returns the eager loader for this association.

@param [ Array<Mongoid::Association> ] associations The

associations to be eager loaded

@param [ Array<Mongoid::Document> ] docs The parent documents

that possess the given associations, which ought to be
populated by the eager-loaded documents.

@return [ Mongoid::Association::Embedded::Eager ]

# File lib/mongoid/association/embedded/embeds_one/proxy.rb, line 190
def eager_loader(associations, docs)
  Eager.new(associations, docs)
end
embedded?() click to toggle source

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

@example Is this association embedded?

Association::Embedded::EmbedsOne.embedded?

@return [ true ] true.

# File lib/mongoid/association/embedded/embeds_one/proxy.rb, line 201
def embedded?
  true
end
new(base, target, association) click to toggle source

Instantiate a new embeds_one association.

@example Create the new proxy.

One.new(person, name, association)

@param [ Document ] base The document this association hangs off of. @param [ Document ] target The child document in the association. @param [ Mongoid::Association::Relatable ] association The association metadata.

Calls superclass method Mongoid::Association::Proxy::new
# File lib/mongoid/association/embedded/embeds_one/proxy.rb, line 33
def initialize(base, target, association)
  super do
    characterize_one(_target)
    bind_one
    characterize_one(_target)
    update_attributes_hash(_target)
    _base._reset_memoized_descendants!
    _target.save if persistable?
  end
end
path(document) click to toggle source

Get the path calculator for the supplied document.

@example Get the path calculator.

Proxy.path(document)

@param [ Document ] document The document to calculate on.

@return [ Mongoid::Atomic::Paths::Embedded::One ]

The embedded one atomic path calculator.
# File lib/mongoid/association/embedded/embeds_one/proxy.rb, line 214
def path(document)
  Mongoid::Atomic::Paths::Embedded::One.new(document)
end

Public Instance Methods

substitute(replacement) click to toggle source

Substitutes the supplied target documents for the existing document in the association.

@example Substitute the new document.

person.name.substitute(new_name)

@param [ Document | Hash ] replacement A document to replace the target.

@return [ Document | nil ] The association or nil.

# File lib/mongoid/association/embedded/embeds_one/proxy.rb, line 53
def substitute(replacement)
  return self if replacement == self

  if _assigning?
    _base.add_atomic_unset(_target) unless replacement
  else
    update_target_when_not_assigning(replacement)
  end

  unbind_one

  return nil if replace_with_nil_document(replacement)

  replace_with(replacement)

  self
end

Private Instance Methods

binding() click to toggle source

Instantiate the binding associated with this association.

@example Get the binding.

relation.binding([ address ])

@return [ Binding ] The association’s binding.

# File lib/mongoid/association/embedded/embeds_one/proxy.rb, line 79
def binding
  Binding.new(_base, _target, _association)
end
persistable?() click to toggle source

Are we able to persist this association?

@example Can we persist the association?

relation.persistable?

@return [ true | false ] If the association is persistable.

# File lib/mongoid/association/embedded/embeds_one/proxy.rb, line 89
def persistable?
  _base.persisted? && !_binding? && !_building? && !_assigning?
end
replace_with(replacement) click to toggle source

Replaces the current document with the given replacement document, which may be a Hash of attributes.

@param [ Mongoid::Document | Hash ] replacement the document to

substitute in place of the current document.
# File lib/mongoid/association/embedded/embeds_one/proxy.rb, line 171
def replace_with(replacement)
  replacement = Factory.build(klass, replacement) if replacement.is_a?(::Hash)
  self._target = replacement
  characterize_one(_target)
  bind_one
  update_attributes_hash(_target)
  _target.save if persistable?
end
replace_with_nil_document(replacement) click to toggle source

Checks the argument. If it is non-nil, this method does nothing. Otherwise, it performs the logic for replacing the current document with nil.

@param [ Mongoid::Document | Hash | nil ] replacement the document

to check.

@return [ true | false ] whether a nil document was substituted

or not.
# File lib/mongoid/association/embedded/embeds_one/proxy.rb, line 150
def replace_with_nil_document(replacement)
  return false if replacement

  update_attributes_hash(replacement)

  # when `touch: true` is the default (see MONGOID-5016), creating
  # an embedded document will touch the parent, and will cause the
  # _descendants list to be initialized and memoized. If the object
  # is then deleted, we need to make sure and un-memoize that list,
  # otherwise when the update happens, the memoized _descendants list
  # gets used and the "deleted" subdocument gets added again.
  _reset_memoized_descendants!

  true
end
update_attributes_hash(replacement) click to toggle source

Update the _base’s attributes hash with the _target’s attributes

@param replacement [ Document | nil ] The doc to use to update the

attributes hash.

@api private

# File lib/mongoid/association/embedded/embeds_one/proxy.rb, line 99
def update_attributes_hash(replacement)
  if replacement
    _base.attributes.merge!(_association.store_as => replacement.attributes)
  else
    _base.attributes.delete(_association.store_as)
  end
end
update_target_when_not_assigning(replacement) click to toggle source

When not “_assigning?“, the target may need to be destroyed, and may need to be marked as a new record. This method takes care of that, with extensive documentation for why it is necessary.

@param [ Mongoid::Document ] replacement the replacement document

# File lib/mongoid/association/embedded/embeds_one/proxy.rb, line 112
def update_target_when_not_assigning(replacement)
  # The associated object will be replaced by the below update if non-nil, so only
  # run the callbacks and state-changing code by passing persist: false in that case.
  _target.destroy(persist: !replacement) if persistable?

  # A little explanation on why this is needed... Say we have three assignments:
  #
  # canvas.palette = palette
  # canvas.palette = nil
  # canvas.palette = palette
  # Where canvas embeds_one palette.
  #
  # Previously, what was happening was, on the first assignment,
  # palette was considered a "new record" (new_record?=true) and
  # thus palette was being inserted into the database. However,
  # on the third assignment, we're trying to reassign the palette,
  # palette is no longer considered a new record, because it had
  # been inserted previously. This is not exactly accurate,
  # because the second assignment ultimately removed the palette
  # from the database, so it needs to be reinserted. Since the
  # palette's new_record is false, Mongoid ends up "updating" the
  # document, which doesn't reinsert it into the database.
  #
  # The change I introduce here, respecifies palette as a "new
  # record" when it gets removed from the database, so if it is
  # reassigned, it will be reinserted into the database.
  _target.new_record = true
end