首先 - 我不会在这里使用 HABTM,而是使用自己的模型命名连接表(称为关系)并使用 has_many :people, through: :relationships。
- 我创建了 2 个人。我希望在查询 Person.first.people 时包含第二个人,反之亦然! (即当我查询 Person.second.people 时,应包括第一个人)。我已经接近通过 has_and_belongs_to_many 实现这一目标:(people|reversed_people): https://stackoverflow.com/a/46230787/6030239
您可以通过为每个关系添加两行(每个方向一个)来使用单个活动记录关系(has-many through 或 HABTM)来实现此目的。例如:
def add_bi_directional_relationship(first:, second:, type:)
Relation.create!(person_a: first, person_b: second, connection: type)
Relation.create!(person_a: second, person_b: first, connection: type)
end
# first.people => [second]
# second.people => [first]
Activerecord 关联旨在通过外键查询表,因此要以简单的方式使用它们,您需要一个表,其中要查询的值将位于单个列中。
但是,为什么需要通过 activerecord 关联来完成呢?您可以编写一个方法来执行您需要的查询。
class Person
has_many :forward_people, through: :relations, #...
has_many :reversed_people, through: :relations, #...
def people
forward_people + reversed_people
# or build the joins in SQL strings or Arel
end
end
或许多其他潜在的解决方案,具体取决于您的需求。
- 将两者联系起来的关系具有朋友的联系价值。我想创建一个 has_many :friends 方法,这样第二个人就会出现在 Person.first.friends 查询中,反之亦然!
不确定我是否完全理解这一点...但是如果您采用第一种方法为每个方向添加关系,那么您可以编写如下方法:
def friends
people.where(relations: {connection: 'friends'})
end
您也可以使用另一个 activerecord 关系来执行此操作...但我不建议为相同的外键定义多个 activerecord 关联。另一种方法是定义一个.friends 范围,允许您执行Person.first.people.friends。
一般来说,这些目标很难实现,因为您正在指定一个实现(返回特定值的 activerecord 关联),而没有说明您为什么需要它来完成它/您试图用它解决什么问题。 Activerecord 关联在一定程度上很有帮助,但它们也引入了一个抽象层,可能会增加复杂性/混乱。讨论您想要解决的实际业务/应用程序需求(例如,显示 X 的报告、呈现 X 的视图或保存 X 的表单)将允许人们提出可能更适合您正在尝试的替代方法完成。