There is opportunity to simplify Mongoid's relation definitions, increase intuitiveness, and at the same time make them more powerful.
One particular issue I'm facing is over-usage of has_and_belongs_to_many ... inverse_of: nil
. The problem with this is that the inverse side of the relationship doesn't trigger any callbacks, which leads to out-of-sync data. It would be more natural to express this as belongs_to_many
and has_many
as per below.
Given two models, each can have the one of the following verbs to define a relation, so long as at least one side is belongs
:
belongs_to_one
(= belongs_to)belongs_to_many
has_one
has_many
belongs_to
implies that this Model stores the foreign key in its fields
has
implies that this Model does NOT store the foreign key in its fields
has_and_belongs_to_many
will NO LONGER be used under this new schema. In ActiveRecord, has_and_belongs_to_many
is actually a shortcut for using a join table (equivalent to has_many ... :through
) and is different than the Mongoid usage anyway, therefore, by dropping it and using different verbs we're not "breaking" compatibility with AR per-se.
This will enable the following canonical cases of relations:
(already supported in Mongoid)
County.belongs_to_one :leader
Leader.has_one :country
Country - leader_id
Leader - id
County.belongs_to_one :leader
Leader.belongs_to_one :country
Country - id country_id
Leader - id country_id
(already supported in Mongoid)
Dog.belongs_to_one :owner
Owner.has_many :dogs
Dog - owner_id
Owner - id
Dog.has_one :owner
Owner.belongs_to_many :dogs
Dog - id
Owner - dog_ids
Dog.belongs_to_one :owner
Owner.belongs_to_many :dogs
Dog - id, owner_id
Owner - id, dog_ids
(can be approximated with has_and_belongs_to_many ... inverse_of: nil
, but the has_many
side won't get callbacks)
Student.belongs_to_many :subjects
Subject.has_many :students
Student - subject_ids
Subject - id
(already supported in Mongoid)
Student.belongs_to_many :subjects
Subject.belongs_to_many :students
Student - id, subject_ids
Subject - id, student_ids
** Not really needed, just adding for sake of completeness
Student.many_to_many :subjects, MyApp.Subject, join_through: "student_subjects"
Student - id
StudentSubjects - subject_id, student_id
Subject - id