问题描述
用户表中的示例数据
rails 控制台中的预期结果,father.children
和 mother.children
应返回同一组对象:
father = User.first
father.children
=> #<ActiveRecord::Associations::CollectionProxy [#<User id: 3,name: "son",father_id: 1,mother_id: 2>,#<User id: 4,name: "daughter",mother_id: 2>]>
mother = User.find(2)
mother.children
=> #<ActiveRecord::Associations::CollectionProxy [#<User id: 3,mother_id: 2>]>
这是我现在在 User.rb 模型中的关联。如果我执行 father.children
,它会返回预期的结果,因为foreign_key 指的是 father_id
。但它不适用于 mother.children
,因为它不引用 mother_id
。
has_many :children,foreign_key: "father_id",class_name: "User"
belongs_to :mother,class_name: "User",optional: true
belongs_to :father,optional: true
有办法吗
foreign key: "father_id" OR "mother_id"
我也尝试在关联中进行查询,但似乎无法理解。
has_many :children,-> { where("father_id = id OR mother_id = id") },class_name: "User"
解决方法
您可以取消该查询创建的默认范围,然后使用用户 ID 过滤子行:
has_many :children,->(user) { unscope(:where).where('father_id = :id OR mother_id = :id',id: user.id) },class_name: "User"
为什么是unscope
?如果不删除它,您的代码将导致两个 SQL 查询,如下所示:
SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT",1]]
SELECT "users".* FROM "users" WHERE "users"."user_id" = ? AND "users"."father_id" = ? [["user_id",1],["father_id","1"]]
执行 User.first.children
时 - 至少在 Rails 6.1.4 中。
如您所见,第二个查询过滤所有用户,id
等于接收者 (1),同时 father_id
列等于接收者 (1)。看看你的代码,可能永远不会发生。
请注意,如果您在声明 has_many
关系后并不真的需要将所有这些方法添加到模型中,则最好使用单个实例方法或作用域(在最后一种情况下)。因为使用这种方法,您会覆盖默认行为(无处记录),即通过该表中的主键过滤另一个表中的行。