具有关联的 Rails 作用域 - (可选)使用关联类的属性筛选作用域



我有一个任务管理应用程序,用户可以在其中创建任务的"等待"。 如果他们正在等待的项目尚未收到,则任务仍处于活动状态。

我正在尝试设置"可操作"范围以包括以下任务:

  • 有一个waiting_for,received_date不是零(他们等待的任何东西都被收到了)
  • 没有等待

    class Task < ActiveRecord::Base 
    has_many :waiting_fors
    def self.actionable
        where("snooze_date <= ? OR snooze_date IS ?", Time.now, nil ).where(complete: false)
        .includes(:waiting_fors).where("waiting_fors.received_date IS NOT ?", nil)
    end
    class WaitingFor < ActiveRecord::Base
        belongs_to :task
    end
    

但是,它向下过滤以仅向我显示项目具有waiting_for的位置以及waiting_for具有received_date的位置。

有什么不好说我哪里

错了?

更新:

这就是我现在所拥有的。 如果任务没有等待或有一个等待已收到,则它正在工作。

scope :not_snoozed, -> {where("snooze_date <= ? OR snooze_date IS ?", Time.now, nil)}
scope :incomplete, -> {where(complete: false)}
scope :no_waiting_fors, -> {includes(:waiting_fors).where(waiting_fors: {id: nil})}
scope :not_received, -> {includes(:waiting_fors).where.not(waiting_fors: {received_date: nil})}
scope :actionable, -> {incomplete.not_snoozed.where(id: (Task.no_waiting_fors+Task.not_received).map(&:id))}

但是,如果一个任务有两个waiting_fors并且只有一个有接收日期(这意味着我们仍在等待某些内容),则它将显示为活动状态。

尝试使用 SQL 的 NOT IN 功能将作用域更新为此:

scope :received, -> {includes(:waiting_fors).where("tasks.id not in (select tasks.id from tasks inner join waiting_fors on waiting_fors.task_id = tasks.id where waiting_fors.received_date is null)")} 
scope :actionable, -> {incomplete.not_snoozed.where(id: (Task.no_waiting_fors+Task.received).map(&:id))}

你的意思是

where("waiting_fors.received_date = ?", nil)

而不是

where("waiting_fors.received_date IS NOT ?", nil)

所有这些都可以通过命名范围轻松实现。您可以为不同的条件构造一个范围,如果要使用多个条件,则可以组合范围。你使用的是 Rails 4 吗?这将是语法:

class Task < ActiveRecord::Base 
has_many :waiting_fors
scope :no_waiting_fors, -> {includes(:waiting_fors).where(waiting_fors: {id: nil})}
scope :not_received, -> {includes(:waiting_fors).where.not(waiting_fors: {received_date: nil})}
scope :actionable, -> {where(id: (Task.no_waiting_fors+Task.not_received).map(&:id))}
end

像这样,您将获得灵活且可扩展的配置。

最新更新