ROR - 如何在父模型的作用域中使用子模型的范围


class Application < ActiveRecord::Base
has_many :documents, class_name: DocumentTracker.name
scope :with_pending_docs, -> {
includes(:documents) {
# not able to use DocumentTracker's scope here
DocumentTracker.status_pending
}
}
#...
end
class DocumentTracker < ActiveRecord::Base
enum: status[:pending, :rejected, :accepted]
scope :status_pending, -> {
where(status: statuses[:pending])
}
}
#...
end

我想执行一些类似的操作:

application = Application.with_pending_docs.find(100)
application.documents.each{ |document|  
# do something with pending docs
}

我可以单独执行此操作,但这会引发额外的查询,如:

application = Application.includes(:documents).find(100) #(2 queries)
docs = application.documents.status_pending #(+1 query)

我可以对单个记录这样做,但它不能达到目的(单个+多个记录查询(:

application = Application.find(100).documents.status_pending

在处理多个应用程序时,会遇到N+1查询问题,因此希望一次性完成

也许,我缺少一些小语法或格式,但还没能使用谷歌搜索找到任何相关内容

Ruby:2.4.1轨道:5.1.0

您需要做类似的事情,就好像您将使用left outer join在纯SQL中编写查询,条件是:

class Application < ActiveRecord::Base
has_many :documents, class_name: DocumentTracker.name
has_many :pending_documents, -> { where({ status: 'pending' }) }, class_name: DocumentTracker.name
scope :with_pending_docs, -> { includes(:pending_documents).where.not(document_trakers: { id: nil }) }
end

然后,您可以在Application的每个实例上调用pending_documents,而无需获得N+1个查询:

Application.with_pending_docs.each { |app| p app.pending_documents }

在尝试了很多关键词后,最终得到了以下答案:https://stackoverflow.com/a/41383726/2902520

我所做的总结(注意,我在Application&DocumentTracker中已经有了一个范围(

#Application Scope
scope :with_pending_docs, -> {
includes(:documents).
merge(DocumentTracker.status_pending)
.references(:documents)
}

查询:

Application.with_pending_docs.find(100)
#or
Application.with_pending_docs.where("applications.id > ?", 100)

希望这对将来的人有所帮助。

最新更新