.. _associations: ************ Associations ************ .. default-domain:: woop .. contents:: On this page :local: :backlinks: none :depth: 2 :class: singlecol Referenced Associations ======================= CouchbaseOrm supports the ``has_many``, ``belongs_to`` and ``has_and_belongs_to_many`` associations familiar to ActiveRecord users. Has Many -------- Use the ``has_many`` association to declare that the parent has zero or more children stored in a separate collection: .. code-block:: ruby class Band < CouchbaseOrm::Base has_many :members end The child model must use ``belongs_to`` to declare the association with the parent: .. code-block:: ruby class Member < CouchbaseOrm::Base belongs_to :band end The child documents contain references to their respective parents: .. code-block:: ruby band = Band.create!(members: [Member.new]) # => # band.members # => [#] Use validations to require that at least one child is present: .. code-block:: ruby class Band < CouchbaseOrm::Base has_many :members validates_presence_of :members end Belongs To ---------- Use the ``belongs_to`` macro to associate a child with a parent stored in a separate collection. The ``_id`` of the parent (if a parent is associated) is stored in the child. .. code-block:: ruby class Studio < CouchbaseOrm::Base belongs_to :band end studio = Studio.create! # => # Although ``has_many`` associations require the corresponding ``belongs_to`` association to be defined on the child, ``belongs_to`` may also be used ``has_many`` macro. In this case the child is not accessible from the parent but the parent is accessible from the child: .. code-block:: ruby class Band < CouchbaseOrm::Base end class Studio < CouchbaseOrm::Base belongs_to :band end Has And Belongs To Many ----------------------- Use the ``has_and_belongs_to_many`` macro to declare a many-to-many association: .. code-block:: ruby class Band < CouchbaseOrm::Base has_and_belongs_to_many :tags end class Tag < CouchbaseOrm::Base has_and_belongs_to_many :bands end Both model instances store a list of ids of the associated models, if any: .. code-block:: ruby band = Band.create!(tags: [Tag.create!]) # => # band.tags # => [#] Custom Association Names ------------------------ You can name your associations whatever you like, but if the class cannot be inferred by CouchbaseOrm from the name, and neither can the opposite side you'll want to provide the macro with some additional options to tell CouchbaseOrm how to hook them up. .. code-block:: ruby class Car < CouchabseOrm::Base belongs_to :engine, class_name: "Motor" end class Motor < CouchabseOrm::Base has_many :machine, class_name: "Car" end Custom Foreign Keys ----------------------------- The attributes used when looking up associations can be explicitly specified. The default is to use ``id`` on the "parent" association and ``#{association_name}_id`` on the "child" association, for example with a has_many/belongs_to: .. code-block:: ruby class Company < CouchbaseOrm::Base has_many :emails end class Email < CouchbaseOrm::Base belongs_to :company end company = Company.find(id) # looks up emails where emails.company_id == company.id company.emails Specify a different ``foreign_key`` to change the attribute name on the "child" association: .. code-block:: ruby class Company < CouchbaseOrm::Base attribute :c, type: String has_many :emails, foreign_key: 'c_ref' end class Email < CouchbaseOrm::Base # This definition of c_ref is automatically generated by CouchbaseOrm: # attribute :c_ref, type: Object # But the type can also be specified: attribute :c_ref, type: String belongs_to :company, foreign_key: 'c_ref' end company = Company.find(id) # looks up emails where emails.c_ref == company.c company.emails Polymorphism ------------ ``has_and_belongs_to_many`` associations support polymorphism, which is having a single association potentially contain objects of different classes. For example, we could model an organization in which departments and teams have managers as follows: .. code-block:: ruby class Department < CouchbaseOrm::Base has_and_belongs_to_many :unit, class_name "Manager" end class Team < CouchbaseOrm::Base has_and_belongs_to_many :unit, class_name "Manager" end class Manager < CouchbaseOrm::Base belongs_to :unit, polymorphic: true end dept = Department.create! team = Team.create! alice = Manager.create!(unit: dept) alice.unit == dept # => true dept.manager == alice # => true .. _dependent-behavior: Dependent Behavior ------------------ You can provide dependent options to referenced associations to instruct CouchbaseOrm how to handle situations where one side of the association is deleted, or is attempted to be deleted. The options are as follows: - ``:destroy``: Destroy the child document(s) and run all of the model callbacks. If no ``:dependent`` option is provided, deleting the parent document leaves the child document unmodified (in other words, the child document continues to reference the now deleted parent document via the foreign key attribute). The child may become orphaned if it is ordinarily only referenced via the parent. .. code-block:: ruby class Band < CouchbaseOrm::Base has_many :albums, dependent: :destroy belongs_to :label end class Album < CouchbaseOrm::Base belongs_to :band end class Label < CouchbaseOrm::Base has_many :bands end Band.first.destroy # Will delete all associated albums.