【问题标题】:Does inverse_of works with has_many?inverse_of 是否与 has_many 一起使用?
【发布时间】:2025-11-29 01:25:01
【问题描述】:

当我使用 has_one 时,它​​可以完美运行,但在 has_many 上却不行。在这里您可以看到 object_id 不同,因为它运行了另一个 SQL 来再次获取它。

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 >

这是我用来设置测试的代码:

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

【问题讨论】:

标签: ruby ruby-on-rails-3 activerecord has-many


【解决方案1】:

不,不是。根据Rails Guide

  • 它们不适用于 :through 关联。
  • 它们不适用于 :polymorphic 关联。
  • 它们不适用于 :as 关联。
  • 对于belongs_to 关联,has_many 反向关联被忽略。

【讨论】:

    【解决方案2】:

    是的!请在此处参考 Active Record 中的关联 API 文档的双向关联部分:http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html

    【讨论】:

    • 是的,我发现these docs 特别令人困惑。该示例给出了has_many :traps, inverse_of: :dungeon,但在下一段中指出:对于belongs_to 关联has_many 反向关联被忽略
    • 直吉的回答是正确的。这个答案要么过时,要么错误。
    【解决方案3】:

    在有关设置 Rails 5 模型的视频的最后一部分中,有一个例子说明了 has_many 关系在没有和 inverse_of 的情况下如何表现。编写 RSpec 测试以确认 object_ids 实际上是相同的:

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

    【讨论】: