Reputation: 13012
I have a system with the following models
class Application < ApplicationRecord
has_many :offers, dependent: :destroy
belongs_to :accepted_offer, class_name: 'Offer',
foreign_key: 'accepted_offer_id',
optional: true
class Offer < ApplicationRecord
belongs_to :application
and was creating a report that gathers all the offers by accepted_offer_id
like thus
Application.find_each do |app|
offer = Offer.find(app.accepted_offer_id) if app.accepted_offer_id
report.push(report_body(app, offer))
end
This is becoming too slow, I would like to rewrite the report bit so that it leverages a left join to make the connection with a sinle query to the db.
I would like to have the query return all offers that are stored as accepted_offer_id
on the applications table.
Offer.left_outer_joins(:applications).where(id: { 'application.accetped_offer_id' })
I know the above is wrong but I am sure it must be possible to get the collection with a single query?
Upvotes: 0
Views: 30
Reputation: 21120
You could also choose to use a sub-query.
offer_ids = Application.select(:accepted_offer_id)
offers = Offer.where(id: offer_ids)
Should result in (MySQL):
SELECT `offers`.*
FROM `offers`
WHERE `offers`.`id` IN (
SELECT `applications`.`accepted_offer_id`
FROM `applications`
)
Upvotes: 0
Reputation: 6445
To rewrite the first bit a bit nicer:
Application.find_each do |app|
report.push(report_body(app, app.accepted_offer)) if app.accepted_offer
end
Moving onto rewriting the SQL, I'm pretty sure what you need to do is:
Offer.joins(:application).where('offers.id = applications.accepted_offer_id')
Upvotes: 1
Reputation: 30056
Anything like this?
class Offer < ApplicationRecord
belongs_to :application
scope :accepted, -> { joins(:application).where('offers.id = applications.accepted_offer_id') }
end
Offer.accepted
Upvotes: 2