Associations#
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:
class Band < CouchbaseOrm::Base
has_many :members
end
The child model must use belongs_to
to declare the
association with the parent:
class Member < CouchbaseOrm::Base
belongs_to :band
end
The child documents contain references to their respective parents:
band = Band.create!(members: [Member.new])
# => #<Band _id: 6001166d4896684910b8d1c5, >
band.members
# => [#<Member _id: 6001166d4896684910b8d1c6, band_id: '6001166d4896684910b8d1c5'>]
Use validations to require that at least one child is present:
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.
class Studio < CouchbaseOrm::Base
belongs_to :band
end
studio = Studio.create!
# => #<Studio _id: 600118184896684987aa884f, band_id: nil>
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:
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:
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:
band = Band.create!(tags: [Tag.create!])
# => #<Band _id: 60011d554896684b8b910a2a, tag_ids: ['60011d554896684b8b910a29']>
band.tags
# => [#<Tag _id: 60011d554896684b8b910a29, band_ids: ['60011d554896684b8b910a2a']>]
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.
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:
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:
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:
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#
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.
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.