0
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

I want to execute something like:

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

I can do this operation separately, but that fires additional queries, like:

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

I can do this for single records , but it's wont serve the purpose (single+multiple records query):

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

There is concern of running into N+1 query issue while working on multiple applications, so want to get it done in one go

Maybe, I am missing minor syntax or formatting, but haven't been able to find anything related using google search

Ruby : 2.4.1 Rails : 5.1.0

mritzi
  • 39
  • 8

2 Answers2

0

You need to do a similar thing as if you would write the query in a pure SQL using left outer join with a condition:

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

Then you can call pending_documents on each instance of Application without getting N+1 queries:

Application.with_pending_docs.each { |app| p app.pending_documents }
Yakov
  • 3,033
  • 1
  • 11
  • 22
  • while I can do that, but I am looking for a way to re-use child record's scope in parent model, and works for single/multiple application records) – mritzi Jul 20 '20 at 16:20
  • I am curious to know how can I use child's scope directly from parent's model. I am hopeful that there is some way to do it, and is hidden somewhere. IMHO, creating two has_many relations for same model may create confusions as well – mritzi Jul 21 '20 at 01:14
  • It is not clear what you want to achieve. Having two relations is quite normal. – Yakov Jul 21 '20 at 04:55
0

After trying a lot of keywords, finally landed at following answer : https://stackoverflow.com/a/41383726/2902520

Summary of what I did (note that I already had one scope in Application & DocumentTracker each)

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

Queries:

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

Hope this helps someone in the future.

mritzi
  • 39
  • 8