红宝石儿童的孩子协会
Posted
技术标签:
【中文标题】红宝石儿童的孩子协会【英文标题】:Association for the child of the child in ruby on rails 【发布时间】:2021-09-25 08:33:50 【问题描述】:User 表中的数据示例
rails 控制台中的预期结果,grandfather.grandchildren
和 grandmother.grandchildren
应该返回同一组对象:
grandfather = User.first
grandfather.grandchildren
=> #<ActiveRecord::Associations::CollectionProxy [#<User id: 5, name: "father's son", father_id: 3, mother_id: nil>, #<User id: 6, name: "uncle's son", father_id: 4, mother_id: nil>]>
grandmother = User.find(2)
grandmother.grandchildren
=> #<ActiveRecord::Associations::CollectionProxy [#<User id: 5, name: "father's son", father_id: 3, mother_id: nil>, #<User id: 6, name: "uncle's son", father_id: 4, mother_id: nil>]>
这是我现在在 User.rb 模型中的关联。
has_many :children, ->(user) unscope(:where).where("father_id = :id OR mother_id = :id", id: user.id) , class_name: "User"
has_many :grandchildren, through: :children, source: :children
belongs_to :mother, class_name: "User", optional: true
belongs_to :father, class_name: "User", optional: true
现在在 Rails 控制台中输出:
irb(main):001:0> grandfather = User.first
(0.3ms) SELECT sqlite_version(*)
User Load (0.2ms) SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ? [["LIMIT", 1]]
=> #<User id: 1, name: "grandfather", mother_id: nil, father_id: nil>
irb(main):002:0> grandfather.grandchildren
User Load (0.3ms) SELECT "users".* FROM "users" INNER JOIN "users" "children_grandchildren" ON "users"."user_id" = "children_grandchildren"."id" WHERE (father_id = 1 OR mother_id = 1) /* loading for inspect */ LIMIT ? [["LIMIT", 11]]
Traceback (most recent call last):
ActiveRecord::StatementInvalid (SQLite3::SQLException: ambiguous column name: father_id)
【问题讨论】:
【参考方案1】:你不能通过孩子从祖父母那里得到孙子,因为这意味着他们的父亲/母亲ID等于祖父母,它不通过孙父母:
SELECT "users".*
FROM "users"
INNER JOIN "users" "children_grandchildren"
ON "users"."user_id" = "children_grandchildren"."id"
WHERE (father_id = 1 OR mother_id = 1) -- this is the grandparent id, when it should be the child parent's id
您可以将 callable 添加到孙子关系中,类似于 children
的关系,但这次提取祖父母子 ID,并使用 IN 子句过滤与那些匹配的用户行ids,以及他们的父亲/母亲 id:
has_many :grandchildren,
->(user) unscope(:where).where('father_id IN (:ids) OR mother_id IN (:ids)', ids: user.children.ids) ,
class_name: "User"
【讨论】:
(0.2ms) SELECT "users"."id" FROM "users" WHERE (father_id = 1 OR mother_id = 1)
(0.2ms) SELECT "users"."id" FROM "users" WHERE (father_id = 1 OR mother_id = 1)
User Load (0.3ms) SELECT "users".* FROM "users" WHERE (father_id IN (3,7) OR mother_id IN (3,7)) /* loading for inspect */ LIMIT ? [["LIMIT", 11]]
出现了三个查询,想知道为什么SELECT "users"."id" FROM "users" WHERE (father_id = 1 OR mother_id = 1)
被查询了两次?是否可以只有一个查询作为输出?答案很有效,谢谢!
是的,我注意到@LeeRenJie,可悲的是,Rails 必须将用户孩子的记录存储在某个地方,所以,可能就是这样。我想,和你之前的问题一样,如果你真的不需要在使用has_many时添加的关系方法,你可以使用一个简单的实例方法。以上是关于红宝石儿童的孩子协会的主要内容,如果未能解决你的问题,请参考以下文章