As outlined here:
http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html
inverse_of appears to tell Rails to Cache the in memory associations and minimize Database Queries. Their example is:
class Dungeon < ActiveRecord::Base
has_many :traps, :inverse_of => :dungeon
has_one :evil_wizard, :inverse_of => :dungeon
end
class Trap < ActiveRecord::Base
belongs_to :dungeon, :inverse_of => :traps
end
Which they immediatly follow with:
for `belongs_to` associations `has_many` inverse associations are ignored.
So I have several questions.
has_many
for a belongs_to
? If so, how does their example make sense? Shouldn't it just not do anything?As far as I can tell (assuming it does anything) All this allows to do is something like:
dungeon.traps.first.dungeon
with the final call to .dungeon
NOT generating an entire new query, but merely reaching for the in memory association. Assuming that is correct, why would I ever NOT want that behavior? Why wouldn't I just stick inverse_of:
on every association?
Rails: When to use :inverse_of in has_many, has_one or belongs_to associations. When you have two models in a has_many , has_one or belongs_to association, the :inverse_of option in Rails tells ActiveRecord that they're two sides of the same association.
From the documentation, it seems like the :inverse_of option is a method for avoiding SQL queries, not generating them. It's a hint to ActiveRecord to use already loaded data instead of fetching it again through a relationship.
has_one means that there is a foreign key in another table that references this class. So has_one can ONLY go in a class that is referenced by a column in another table.
I started writing about rails inflector and how when an association isn't a straight inflection of a model you use inverse_of to indicate what it is. But then I scrolled to the section you mention and this is how I see it. Say you have something like:
# let's pick a dungeon
d = Dungeon.first
# say you find also find a trap that belongs to this particular d
t = Trap.find(...)
# then t.dungeon is the exact same object as d
d == t.dungeon
Of course dungeon.traps.first.dungeon
doesn't really make sense and I doubt that's why this exists. Personally I don't see where and how I would use this but the example they give seems to fill a use case. It goes like this:
# you have an attribute level on dungeon
d.level # => 5
# now say you have a comparison after a modification to level
d.level = 10
# now without inverse_of the following thing occurs
d.level # => 10
t.dungeon.level # => 5
# d was updated and since t.dungeon is a whole different object
# it doesn't pick up the change and is out of sync but using invers_of you get
d.level # => 10
t.dungeon.level # => 10
# because d and t.dungeon are the very same object
Hope that clarifies things.
Great news! In Rails 4.1 basic associations* will automatically set up inverse_of
.
*More convenience means more edge cases... automatic inverse_of only works for associations that do not specify any of the following options:
:through
:foreign_key
:conditions
:polymorphic
Resources:
http://edgeguides.rubyonrails.org/4_1_release_notes.html http://wangjohn.github.io/activerecord/rails/associations/2013/08/14/automatic-inverse-of.html
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With