ActiveRecord查询基于关联记录的状态

时间:2016-04-15 14:11:21

标签: ruby-on-rails activerecord

我在ActiveRecord中构建此查询时遇到问题:

返回没有完成或活动打印作业的唯一文档列表。

因此,查询应包括根本没有打印作业或仅中止打印作业的文档。

以下是模型和相关属性:

class Document < ActiveRecord::Base
  has_many :print_jobs
end

class PrintJob < ActiveRecord::Base
  enum status: { active: 0, completed: 1, aborted: 2 }

  belongs_to :document
end

我的第一次尝试是获取所有已完成或活动的打印作业的列表,并找到与这些打印作业无关的所有文档:

Document.where.not(id: PrintJob.active_or_completed.select(:document_id))

但我想知道这是否是正确的“SQL-ish”方式进行此类查询。

提前感谢您的帮助!

4 个答案:

答案 0 :(得分:1)

我认为你这样做的方式绝对有道理。添加@Aleks建议的小优化:

picker.delegate = self
picker2.delegate = anotherClassInstance

编辑:更新以反映讨论的最新状态。删除了使用采摘的建议。这里没用。

答案 1 :(得分:0)

Document.joins(:print_jobs).where.not(status: [0,1]).uniq应该完成这项工作。

答案 2 :(得分:0)

这是所有SQL方法,无需选择id's并运行两个单独的查询:

Document.includes(:print_jobs).where.not( :print_jobs => { status: [statuses[:active], statuses[:completed]] } )

它将选择所有可以加入状态有效或已完成的PrintJobs的文档

答案 3 :(得分:0)

我建议在Document模型中创建一个特殊范围,它只会返回所需的结果。因为您不应该将您的查询逻辑暴露出模型。 此外,最好将相应的范围添加到PrintJob模型中,这样就可以在Document for stroped PrintJob中定义额外的has_many关联。

正如Aleks已经提到的那样,最好在数据库层上完成所有工作并且不要提取PrintJob的所有ID并将它们传递给查询,因为它可能会降低性能显著。因此,使用单个SQL查询进行此操作会更好。

class Document < ActiveRecord::Base
  has_many :print_jobs

  # Here we can define association with scope which applies scope defined in PrintJob
  has_many :not_active_or_completed_print_jobs, -> { not_active_or_completed }, class_name: 'PrintJob'

  # I believe that there is a shorter name exists for such sort of documents
  def self.without_active_or_completed_jobs
    distinct.joins(:not_active_or_completed_print_jobs)
  end
end

class PrintJob < ActiveRecord::Base
  enum status: { active: 0, completed: 1, aborted: 2 }

  belongs_to :document

  def self.not_active_or_completed
    where.not(status: [statuses[:active], statuses[:completed]])
  end
end

之后你可以这样称呼它:

Document.without_active_or_completed_jobs