This is part of the Semicolon&Sons Code Diary - consisting of lessons learned on the job. You're in the rails category.
Last Updated: 2024-11-21
I had the following code, which, due to Rails defaults, means both the tutor
and law_discipline
are mandatory.
class LawDisciplineOffering < ApplicationRecord
belongs_to :tutor
belongs_to :law_discipline
end
I then wrote the following caller code:
tutor = Tutor.new(...)
tutor.law_discipline_offerings.build({...})
tutor.save!
It failed, saying that tutor_id
must be present — i.e. it was unable to
associate the law_discipline_offering
to the un-persisted tutor
on the prior
line that I just instantiated.
This was fixed by adding inverse_of
here and also in the LawDiscipline
model.
class LawDisciplineOffering < ApplicationRecord
belongs_to :tutor, inverse_of: :law_discipline_offerings
belongs_to :law_discipline, inverse_of: :law_discipline_offerings
end
It turns out that associated objects do not point to in-memory objects by default. To illustrate:
prison = Prison.create(name: 'Bad House')
criminal = prison.criminals.create(name: 'Krazy 8')
# Without :inverse_of, an SQL query must be executed
criminal.prison == prison
# Prison Load (0.1ms) SELECT "prisons".* FROM "prisons" WHERE "prisons"."id" = 2 LIMIT 1
# => true
# With :inverse_of, no SQL query happens. It can handle in-memory objects.
criminal.prison == prison
# => true
By default,, a model's associations, as far as memory is concerned, are one-way bindings. The
:inverse_of
option basically gives us two-way memory bindings.