Exploring the :inverse_of option on rails model association
Let's start with the basic models and defining inverse of relationship in these models:
When we call
It's worth clarifying that this only saves you a database look-up when going from
A model's associations, as far as memory is concerned, are one-way bindings. The
class Criminal < ActiveRecord::Base
belongs_to :prison, inverse_of: :criminals
end
class Prison < ActiveRecord::Base
has_many :criminals, inverse_of: :prison
end
Memory Optimization When Fetching Associated Records
It turns out that associated objects do not point to the same in-memory objects by default. To illustrate:
prison = Prison.create(name: 'Bad House')
criminal = prison.criminals.create(name: 'Krazy 8')
# Without :inverse_of
criminal.prison == prison
# Prison Load (0.1ms) SELECT "prisons".* FROM "prisons" WHERE "prisons"."id" = 2 LIMIT 1 # => true
# With :inverse_of
criminal.prison == prison
# => true
When we call
criminal.prison
without :inverse_of
on both the :belongs_to
and :has_many
associations, it will hit the database. With :inverse_of
, if we already have that prison record in memory then criminal.prison
will point to the same prison.It's worth clarifying that this only saves you a database look-up when going from
Criminal
to Prison
(:belongs_to
direction). Here's some console output going from the other direction:
prison = Prison.last
# Prison Load (0.1ms) SELECT "prisons".* FROM "prisons" ORDER BY "prisons"."id" DESC LIMIT 1 # => #<Prison id: 3, name: "Broadmoor", created_at: "2014-10-10 20:26:38", updated_at: "2014-10-10 20:26:38">
criminal = prison.criminals.first
# Criminal Load (0.3ms) SELECT "criminals".* FROM "criminals" WHERE "criminals"."prison_id" = 3 LIMIT 1 # => #<Criminal id: 3, name: "Charles Bronson", prison_id: 3, created_at: "2014-10-10 20:26:47", updated_at: "2014-10-10 20:26:47">
prison.criminals.first == criminal
# Criminal Load (0.2ms) SELECT "criminals".* FROM "criminals" WHERE "criminals"."prison_id" = 3 LIMIT 1 # => true
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 when one of the associations is a :belongs_to
. A memory optimization isn't the only thing that :inverse_of
gets you.
Comments
Post a Comment