Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why would I NOT want to use inverse_of everywhere?

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.

  1. Are inverse associations ignored on has_many for a belongs_to? If so, how does their example make sense? Shouldn't it just not do anything?
  2. 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?

like image 609
Abraham P Avatar asked Feb 18 '13 00:02

Abraham P


People also ask

When to use inverse_ of Rails?

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.

What is Inverse_of?

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.

What is has_ one Rails?

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.


2 Answers

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.

like image 179
Hugo Avatar answered Sep 30 '22 15:09

Hugo


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

like image 25
cjav_dev Avatar answered Sep 30 '22 15:09

cjav_dev