如何基于关联表字段对acts_as_list进行作用域限定?
解决acts_as_list跨关联表设置作用域的问题
你直接在acts_as_list的scope参数里使用todo.status的写法无法生效,因为默认的数组格式scope只支持当前模型的属性或关联对象,不支持关联对象的嵌套属性。这里提供两种无需冗余存储status的可行方案:
方案一:使用Lambda定义动态关联作用域
利用acts_as_list支持Lambda作为scope参数的特性,通过关联查询筛选出符合条件的记录范围:
class SprintTodo < ApplicationRecord belongs_to :sprint belongs_to :todo acts_as_list scope: ->(record) { joins(:todo).where(sprint_id: record.sprint_id, todos: { status: record.todo.status }) } end
这个Lambda会接收当前的SprintTodo实例作为参数,通过joins(:todo)关联到Todo表,然后筛选出同一Sprint下、关联Todo状态相同的所有SprintTodo记录,以此作为acts_as_list维护position的作用域。
方案二:抽离独立作用域方法
如果希望代码更清晰,可先定义一个命名作用域,再在acts_as_list中引用:
class SprintTodo < ApplicationRecord belongs_to :sprint belongs_to :todo scope :same_sprint_and_todo_status, ->(record) { joins(:todo).where(sprint_id: record.sprint_id, todos: { status: record.todo.status }) } acts_as_list scope: :same_sprint_and_todo_status end
注意事项
- 为避免JOIN查询性能问题,建议给
todos(status)、sprint_todos(sprint_id)添加数据库索引;如果查询频繁,也可以考虑添加sprint_todos(sprint_id, todo_id)的联合索引。 - 不要采用冗余存储
status的方案,否则当Todo的status更新时,需要额外同步SprintTodo中的冗余字段,极易引发数据一致性问题。
内容的提问来源于stack exchange,提问作者Sawaid
相关产品推荐
相关产品推荐

