lib/mongoid/association/referenced/has_and_belongs_to_many/binding.rb
# frozen_string_literal: true
# rubocop:todo all
module Mongoid
module Association
module Referenced
class HasAndBelongsToMany
# Binding class for all has_and_belongs_to_many associations.
class Binding
include Bindable
# Binds a single document with the inverse association. Used
# specifically when appending to the proxy.
#
# @example Bind one document.
# person.preferences.bind_one(preference)
#
# @param [ Document ] doc The single document to bind.
def bind_one(doc)
binding do
inverse_keys = try_method(doc, _association.inverse_foreign_key) unless doc.frozen?
if inverse_keys
record_id = inverse_record_id(doc)
unless inverse_keys.include?(record_id)
try_method(doc, _association.inverse_foreign_key_setter, inverse_keys.push(record_id))
end
doc.reset_relation_criteria(_association.inverse)
end
_base._synced[_association.foreign_key] = true
doc._synced[_association.inverse_foreign_key] = true
end
end
# Unbind a single document.
#
# @example Unbind the document.
# person.preferences.unbind_one(document)
def unbind_one(doc)
binding do
_base.send(_association.foreign_key).delete_one(record_id(doc))
inverse_keys = try_method(doc, _association.inverse_foreign_key) unless doc.frozen?
if inverse_keys
inverse_keys.delete_one(inverse_record_id(doc))
doc.reset_relation_criteria(_association.inverse)
end
_base._synced[_association.foreign_key] = true
doc._synced[_association.inverse_foreign_key] = true
end
end
# Find the inverse id referenced by inverse_keys
#
# @param [ Mongoid::Document ] doc The document for which
# to determine the inverse id.
#
# @return [ BSON::ObjectId ] The inverse id.
def inverse_record_id(doc)
if pk = _association.options[:inverse_primary_key]
_base.send(pk)
else
inverse_association = determine_inverse_association(doc)
if inverse_association
_base.__send__(inverse_association.primary_key)
else
_base._id
end
end
end
# Find the inverse association given a document.
#
# @param [ Mongoid::Document ] doc The document for which
# to determine the inverse association.
#
# @return [ Mongoid::Association::Relatable ] The inverse association.
def determine_inverse_association(doc)
doc.relations[_base.class.name.demodulize.underscore.pluralize]
end
end
end
end
end
end