我有一个Project模型,可以将自身作为定义为Project.projects的子项目。
class Project < ApplicationRecord
belongs_to :parent_project, class_name: 'Project', optional: true
has_many :projects, foreign_key: :parent_project_id, class_name: 'Project', dependent: :destroy
has_many :goals
end
每个项目都有许多目标。
[我正在尝试在Project模型中编写一种方法,该方法将使我能够收集该项目的所有目标,以及所有子项目的子项目(递归)。
def descendant_projects
self.projects | self.projects.map(&:descendant_projects).flatten
end
def goals_including_descendants
all_goals = self.goals
descendant_projects.each do |project|
all_goals.concat(project.goals)
end
all_goals
end
[当我调用project.goals_includes_descendants时,将在数据库中更新子项目的project_id,以将其作为原始父项目的直接目标。此代码的哪一部分将导致Rails触发数据库更新?我可以在控制台中看到它:
Goal Load (0.0ms) SELECT "goals".* FROM "goals" WHERE "goals"."project_id" = $1 [["project_id", 49]]
(0.0ms) BEGIN
SQL (0.2ms) UPDATE "goals" SET "project_id" = $1, "updated_at" = $2 WHERE "goals"."id" = $3 [["project_id", 1], ["updated_at", "2020-05-14 20:47:47.761861"], ["id", 19]]
我完全为为什么发生这种情况而感到困惑。感谢您的见解。
因为concat
将项目添加到self.goals
AR Relation对象并立即更新,所以发生。
您可以通过将其转换为数组来解决此问题。
all_goals = self.goals.to_a
descendant_projects.each do |project|
all_goals << project.goals.to_a
end
all_goals.flatten
将在最后返回一个数组,它可能不是您想要的。
另一种方法是获取所有ID。最后将返回一个Relation / Enumerable。
all_goals_ids = self.goals.ids
descendant_projects.each do |project|
all_goals_ids << project.goals.ids
end
Goal.where(id: all_goals_ids)