lib/mongoid/association.rb
# frozen_string_literal: true
# rubocop:todo all
require 'mongoid/association/accessors'
require 'mongoid/association/builders'
require 'mongoid/association/bindable'
require 'mongoid/association/depending'
require 'mongoid/association/proxy'
require 'mongoid/association/many'
require 'mongoid/association/one'
require 'mongoid/association/relatable'
require 'mongoid/association/nested'
require 'mongoid/association/referenced'
require 'mongoid/association/embedded'
require 'mongoid/association/macros'
require 'mongoid/association/reflections'
require 'mongoid/association/eager_loadable'
module Mongoid
# Mixin module which adds association behavior to a Mongoid document.
# Adds methods such as #embedded? which indicate a document's
# relative association state.
module Association
extend ActiveSupport::Concern
include Embedded::Cyclic
include Referenced::AutoSave
include Referenced::CounterCache
include Referenced::Syncable
include Accessors
include Depending
include Builders
include Macros
include Reflections
# Map the macros to their corresponding Association classes.
#
# @return [ Hash ] The mapping from macros to their Association class.
MACRO_MAPPING = {
embeds_one: Association::Embedded::EmbedsOne,
embeds_many: Association::Embedded::EmbedsMany,
embedded_in: Association::Embedded::EmbeddedIn,
has_one: Association::Referenced::HasOne,
has_many: Association::Referenced::HasMany,
has_and_belongs_to_many: Association::Referenced::HasAndBelongsToMany,
belongs_to: Association::Referenced::BelongsTo,
}.freeze
attr_accessor :_association
included do
class_attribute :polymorphic
self.polymorphic = false
end
# Determine if the document itself is embedded in another document via the
# proper channels. (If it has a parent document.)
#
# @example Is the document embedded?
# address.embedded?
#
# @return [ true | false ] True if the document has a parent document.
def embedded?
@embedded ||= (cyclic ? _parent.present? : self.class.embedded?)
end
# Determine if the document is part of an embeds_many association.
#
# @example Is the document in an embeds many?
# address.embedded_many?
#
# @return [ true | false ] True if in an embeds many.
def embedded_many?
_association && _association.is_a?(Association::Embedded::EmbedsMany)
end
# Determine if the document is part of an embeds_one association.
#
# @example Is the document in an embeds one?
# address.embedded_one?
#
# @return [ true | false ] True if in an embeds one.
def embedded_one?
_association && _association.is_a?(Association::Embedded::EmbedsOne)
end
# Get the association name for this document. If no association was defined
# an error will be raised.
#
# @example Get the association name.
# document.association_name
#
# @raise [ Errors::NoMetadata ] If no association metadata is present.
#
# @return [ Symbol ] The association name.
def association_name
raise Errors::NoMetadata.new(self.class.name) unless _association
_association.name
end
# Determine if the document is part of an references_many association.
#
# @example Is the document in a references many?
# post.referenced_many?
#
# @return [ true | false ] True if in a references many.
def referenced_many?
_association && _association.is_a?(Association::Referenced::HasMany)
end
# Determine if the document is part of an references_one association.
#
# @example Is the document in a references one?
# address.referenced_one?
#
# @return [ true | false ] True if in a references one.
def referenced_one?
_association && _association.is_a?(Association::Referenced::HasOne)
end
# Convenience method for iterating through the loaded associations and
# reloading them.
#
# @example Reload the associations.
# document.reload_relations
#
# @return [ Hash ] The association metadata.
def reload_relations
relations.each_pair do |name, meta|
if instance_variable_defined?("@_#{name}")
if _parent.nil? || instance_variable_get("@_#{name}") != _parent
remove_instance_variable("@_#{name}")
end
end
end
end
end
end