我认为这个查询错了吗?

Am I thinking this query wrong?

我的联想(简体):

项目

has_many :users
has_many :tasklists

任务列表

has_many :tasks

任务

belongs_to :tasklist

用户

has_many :assigned_tasks, class_name: 'Task', foreign_key: 'assignee_id'

我想做什么

我想显示项目资源,其中包含项目用户,每个用户都包含分配给他们的任务。

我试过了:

project = Project.includes(users: :assigned_tasks).find(params[:id])

除了 returns 甚至不属于父项目的 assigned_tasks 之外,这种类型的作品。这不是我想要的。我只想要作为该项目子项的已分配任务。

也许整个方法都不对。也许我应该首先考虑任务,例如:

project = Project.includes(tasklists: :tasks)

但是我将如何按用户组织任务?

我希望我说得有道理。任何帮助将不胜感激。 谢谢

有多种方法可以解决此问题,具体取决于您的优先级。让我们从查看您的第一个查询开始:

project = Project.includes(users: :assigned_tasks).find(params[:id])

这样做的优点是您只执行一个数据库查询来提取所有信息 - 缺点是您要返回 所有 分配的任务,而不是只是这个项目的那些。但是您总是可以在显示任务时过滤它们:

project.users.each do |user|
  user.assigned_tasks.select {|t| t.project_id == project.id}.each do |task|
    puts task
  end
end

或者,您可以先检索项目及其用户:

project = Project.includes(:users).find(params[:id])

add a scope to your Task with a where clause on the join 只查找该项目的任务:

class Task < ActiveRecord::Base
  belongs_to :tasklist
  scope :for_project, -> (project) {joins(:tasklist).where(tasklist: {project: project})} 
end

那么在显示任务的时候就可以使用这个作用域了:

project.users.each do |user|
  user.assigned_tasks.for_project(project).each do |task|
    puts task
  end
end

这样做的缺点是您可能 运行 进入 N+1 queries problem。这也不是清晰度的重大进步。


也许最好的方法是允许从 project 对象直接访问项目的任务:

class Project < ActiveRecord::Base
  has_many :users
  has_many :tasklists
  has_many :tasks, through: :tasklists
end

class Task < ActiveRecord::Base
  belongs_to :tasklist
  has_one :project, through: :tasklist
end

这允许您通过 project.tasks 访问项目的任务。关联是 Enumerable, so you can use group_by 就像你对任何数组一样:

project.tasks.group_by(&:user).each do |user, tasks]
  puts user.name
  tasks.each do |t|
    puts t
  end
end

为了保持较低的数据库查询数量,您可以使用项目加载任务:

project = Project.includes(:users, :tasks).find(params[:id])