Rails中如何按状态条件从关联表获取对应任务的最后记录?
解决方案:基于任务最终状态筛选任务
这个需求的核心是要找出每个任务的最终状态(也就是优先级最高的状态,这里状态ID越大优先级越高:已完成(4) > 暂停(3) > 运行中(2) > 已启动(1)),然后筛选那些最终状态匹配目标值的任务。
思路拆解
每个任务可能有多条状态记录,我们需要先对每个任务的状态分组,找到它的最高优先级状态(用MAX(status_id)即可实现),再筛选出最高状态等于目标值的任务。
代码实现
1. 直接获取符合条件的task_id
如果只需要返回任务ID,可以直接通过TaskStatus模型查询:
# 搜索「运行中」(status_id=2)的task_id running_task_ids = TaskStatus.group(:task_id).having('MAX(status_id) = ?', 2).pluck(:task_id) # 返回结果: [2] # 搜索「已完成」(status_id=4)的task_id completed_task_ids = TaskStatus.group(:task_id).having('MAX(status_id) = ?', 4).pluck(:task_id) # 返回结果: [1]
2. 获取完整的Task对象
如果需要返回对应的Task实例,需要确保模型之间的关联正确,再通过关联查询实现:
首先确认模型关联:
# app/models/task.rb class Task < ApplicationRecord has_many :task_statuses end # app/models/task_status.rb class TaskStatus < ApplicationRecord belongs_to :task end
然后执行查询:
# 获取所有「运行中」的Task对象 running_tasks = Task.joins(:task_statuses) .group('tasks.id') .having('MAX(task_statuses.status_id) = ?', 2) # 获取所有「已完成」的Task对象 completed_tasks = Task.joins(:task_statuses) .group('tasks.id') .having('MAX(task_statuses.status_id) = ?', 4)
3. 子查询方式(更清晰的逻辑)
如果觉得分组查询不够直观,也可以用子查询先找出每个任务的最终状态,再关联筛选:
# 子查询:获取每个task_id对应的最高状态 final_status_subquery = TaskStatus.select('task_id, MAX(status_id) as max_status').group(:task_id) # 筛选「运行中」的任务 running_tasks = Task.joins("INNER JOIN (#{final_status_subquery.to_sql}) sub ON tasks.id = sub.task_id") .where('sub.max_status = ?', 2) # 筛选「已完成」的任务 completed_tasks = Task.joins("INNER JOIN (#{final_status_subquery.to_sql}) sub ON tasks.id = sub.task_id") .where('sub.max_status = ?', 4)
为什么这样可行?
因为你的数据中:
- Task 1的状态记录包含1、2、3、4,最高状态是4(已完成),所以只会在搜索「已完成」时被匹配
- Task 2的状态记录包含1、2,最高状态是2(运行中),所以只会在搜索「运行中」时被匹配
完全符合你的需求~
内容的提问来源于stack exchange,提问作者Krunal Shah
相关产品推荐
相关产品推荐

