Does inverse_of works with has_many?
Asked Answered
S

3

5

When I use has_one it works perfectly, but not on the has_many. Here you can see that the object_id is different because it ran another SQL to fetch it again.

ruby-1.9.2-p290 :001 > e = Employee.create(name: 'rafael', active: false)
ruby-1.9.2-p290 :002 > b = Badge.create(number: 1, employee: e)
ruby-1.9.2-p290 :003 > a = Address.create(street: "123 Market St", city: "San Diego", employee: e)
ruby-1.9.2-p290 :004 > e = Employee.first
  Employee Load (0.2ms)  SELECT "employees".* FROM "employees" LIMIT 1
 => #<Employee id: 1, name: "rafael", active: false, created_at: "2011-10-04 17:09:25", updated_at: "2011-10-04 17:09:25"> 
ruby-1.9.2-p290 :002 > e.is_active?
 => false 
ruby-1.9.2-p290 :003 > e.object_id
 => 2182895380 
ruby-1.9.2-p290 :004 > e.badge.employee.is_active?
  Badge Load (17.6ms)  SELECT "badges".* FROM "badges" WHERE "badges"."employee_id" = 1 LIMIT 1
 => false 
ruby-1.9.2-p290 :005 > e.badge.employee.object_id
 => 2182895380 
ruby-1.9.2-p290 :006 > e.addresses.first.employee.is_active?
  Address Load (0.2ms)  SELECT "addresses".* FROM "addresses" WHERE "addresses"."employee_id" = 1 LIMIT 1
  Employee Load (0.3ms)  SELECT "employees".* FROM "employees" WHERE "employees"."id" = 1 LIMIT 1
 => false 
ruby-1.9.2-p290 :007 > e.addresses.first.employee.object_id
  Address Load (0.3ms)  SELECT "addresses".* FROM "addresses" WHERE "addresses"."employee_id" = 1 LIMIT 1
  Employee Load (0.2ms)  SELECT "employees".* FROM "employees" WHERE "employees"."id" = 1 LIMIT 1
 => 2181302220 
ruby-1.9.2-p290 :008 >

Here is the code that I used to setup my test:

class Employee < ActiveRecord::Base
  has_many :addresses, :inverse_of => :employee
  has_one :badge, :inverse_of => :employee

  accepts_nested_attributes_for :addresses
  accepts_nested_attributes_for :badge
  # validates_associated :addresses

  def is_active?
    active
  end
end

class Address < ActiveRecord::Base
  belongs_to :employee, :inverse_of => :addresses

  validates :city, length: { within: 100..1000, message: "Too short"}, :if => lambda {|a| a.employee.is_active?}
end

class Badge < ActiveRecord::Base
  belongs_to :employee, :inverse_of => :badge

  validates :number, length: { within: 2..10, message: "Too long"}, :if => lambda {|b| b.employee.is_active?}
end
Sugary answered 4/10, 2011 at 21:21 Comment(1)
possible duplicate of ActiveRecord :inverse_of does not work on has_many :through on the join model on createErythrocyte
T
4

Yes it does! Please reference the Bi-Directional Associations section of the API docs for Associations in Active Record here: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

Tequila answered 4/10, 2011 at 23:48 Comment(2)
Yeah, I find these docs specifically very confusing. The example gives has_many :traps, inverse_of: :dungeon, but in the next paragraph states: for belongs_to associations has_many inverse associations are ignored.Pregnable
Naoyoshi's answer is correct. This answer is either out of date or wrong.Tannate
C
5

No it isn't. According to Rails Guide,

  • They do not work with :through associations.
  • They do not work with :polymorphic associations.
  • They do not work with :as associations.
  • For belongs_to associations, has_many inverse associations are ignored.
Cumings answered 27/5, 2013 at 8:11 Comment(0)
T
4

Yes it does! Please reference the Bi-Directional Associations section of the API docs for Associations in Active Record here: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

Tequila answered 4/10, 2011 at 23:48 Comment(2)
Yeah, I find these docs specifically very confusing. The example gives has_many :traps, inverse_of: :dungeon, but in the next paragraph states: for belongs_to associations has_many inverse associations are ignored.Pregnable
Naoyoshi's answer is correct. This answer is either out of date or wrong.Tannate
J
0

In the last part of this video about setting up Rails 5 models there's an example of how a has_many relationship behaves without, and then with the inverse_of. An RSpec test is written to confirm object_ids are in fact the same:

https://www.youtube.com/watch?v=5sfufoY59Ek&feature=youtu.be&t=42m54s

Jaimiejain answered 20/8, 2016 at 4:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.