ruby-on-rails Rails has_many:through关联使用错误的外键进行查询

d8tt03nd  于 2022-12-15  发布在  Ruby
关注(0)|答案(1)|浏览(217)

导轨7.0.4
我有两个Rails模型,PersonMarriage,其思想是一个Person可以通过一个Marriage连接模型拥有多个妻子和丈夫,并且可以调用Person.wivesPerson.husbands来获取各自的数据。
型号代码:

class Person < ApplicationRecord
    has_many :marriages
    has_many :husbands, through: :marriages, class_name: 'Person' 
    has_many :wives, through: :marriages, class_name: 'Person' 
end

class Marriage < ApplicationRecord
    belongs_to :husband, class_name: 'Person'
    belongs_to :wife, class_name: 'Person'
end

婚姻移民法:

class CreateMarriages < ActiveRecord::Migration[7.0]
  def change
    create_table :marriages do |t|
      t.references :husband, foreign_key: { to_table: :people }, index: true
      t.references :wife, foreign_key: { to_table: :people }, index: true
      t.date :marriage_date
      t.date :termination_date

      t.timestamps
    end
  end
end

已在控制台上使用此创建人员和婚姻:

husband = Person.first
wife = Person.second
Marriage.create(husband: husband, wife: wife)

但是,调用husband.wives将返回

Person Load (0.3ms)  SELECT "people".* FROM "people" INNER JOIN "marriages" ON "people"."id" = "marriages"."wife_id" WHERE "marriages"."person_id" = ?  [["person_id", 1]]                                                     
(Object doesn't support #inspect)                                  
=>

看起来查询的最后一部分,寻找marriages.person_id,是错误的,因为我期望它使用marriages.husband_id。如何使它使用正确的外键?
我尝试过向关联中添加选项,例如foreign_key: :wife_idsource: :husbandinverse_of: :wifehas_many :husbands,在has_many :wives上也是如此,但出现了相同的结果。

bmp9r5qi

bmp9r5qi1#

实际上,您不能将一个has_many关联与 other 表中的两个不同外键一起使用,而是需要两个不同的关联:

class Person < ApplicationRecord
   has_many :marriages_as_wife, 
     class_name: 'Marriage',
     foreign_key: :wife_id,
     inverse_of: :wife
   has_many :marriages_as_husband, 
     class_name: 'Marriage',
     foreign_key: :husband_id,
     inverse_of: :husband
    
   has_many :husbands, 
     through: :marriages_as_wife, 
     class_name: 'Person' 
   has_many :wives, 
     through: :marriages_as_husband, 
     class_name: 'Person' 
end

inverse_of实际上不会以任何方式改变生成的查询,它只是用来在内存中设置引用,以避免潜在的额外数据库查询。
顺便说一句,我可能会使用一个非常不同的解决方案,使用多对多连接表,以避免做出异规范性假设:

class Person
  has_many :marriage_memberships
  has_many :marriages, 
    through: :marriage_memberships
  has_many :spouses, 
    through: :marriages,
    source: :people
end

class Marriage
  has_many :marriage_memberships
  has_many :people, through: :marriage_memberships
end 

# I can't come up with a better name
class MarriageMemberships
  belongs_to :person
  belongs_to :marriage
end

相关问题