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.
Their example:
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
class EvilWizard < ActiveRecord::Base
belongs_to :dungeon, :inverse_of => :evil_wizard
end
In this case, calling dungeon.traps.first.dungeon
should return the original dungeon
object instead of loading a new one as would be the case by default.
I think :inverse_of
is most useful when you are working with associations that have not yet been persisted. E.g.:
class Project < ActiveRecord::Base
has_many :tasks, :inverse_of=>:project
end
class Task < ActiveRecord::Base
belongs_to :project, :inverse_of=>:tasks
end
Now, in the console:
irb> p = Project.new
=> #<Project id: nil, name: nil, ...>
irb> t = p.tasks.build
=> #<Task id: nil, project_id: nil, ...>
irb> t.project
=> #<Project id: nil, name: nil, ...>
Without the :inverse_of
arguments, t.project
would return nil
, because it triggers an sql query and the data isn't stored yet. With the :inverse_of
arguments, the data is retrieved from memory.
After this pr (https://github.com/rails/rails/pull/9522) inverse_of is not required in most cases.
Active Record supports automatic identification for most associations with standard names. However, Active Record will not automatically identify bi-directional associations that contain a scope or any of the following options:
class Author < ApplicationRecord
has_many :books, inverse_of: 'writer'
end
class Book < ApplicationRecord
belongs_to :writer, class_name: 'Author', foreign_key: 'author_id'
end
a = Author.first
b = a.books.first
a.first_name == b.writer.first_name # => true
a.first_name = 'David'
a.first_name == b.writer.first_name # => true
In the above example, a reference to the same object is stored in the variable a
and in the attribute writer
.
When we have 2 models with has_many and belongs_to relationship, it's always better to use inverse_of which inform ActiveRecod that they belongs to the same side of the association. So if a query from one side is triggered, it will cache and serve from cache if it get triggered from the opposite direction. Which improves in performance. From Rails 4.1, inverse_of will be set automatically, if we uses foreign_key or changes in class name we need to set explicitly.
Best article for details and example.
http://viget.com/extend/exploring-the-inverse-of-option-on-rails-model-associations
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