I have a deeply nested layout as follows:
Contract -> has many Packages -> has many Services
Payment -> belongs_to Invoice -> belongs_to Contract
class Contract < ActiveRecord::Base
has_many :invoices
has_many :contract_packages
has_many :packages, through: :contract_packages
end
class Package < ActiveRecord::Base
has_many :services
has_many :contract_packages
has_many :contracts, through: :contract_packages
end
class ContractPackage < ActiveRecord::Base
belongs_to :contract
belongs_to :package
end
class Service < ActiveRecord::Base
belongs_to :package
end
class Invoice < ActiveRecord::Base
belongs_to :contract
end
class Payment < ActiveRecord::Base
belongs_to :invoice
end
I want to find what Services, and how many times were invoiced in a certain period of time, based on payment date. Invoice date may not be the same as payment date.
I know hot to do it by pure SQL, and it works, but I am stuck if I want to do it the rails way.
Any ideas?
Edit:
The pure sql query:
select s.[name], count(*), s.[price] from payments p
left join invoices i on p.invoice_id=i.id
left join contracts c on i.[contract_id]=c.id
left join contract_packages cp on cp.contract_id=c.id
left join packages pk on cp.[package_id]=pk.id
left join services s on s.package_id=pk.id
where ... conditions
group by s.id
order by s.id asc
In my original question I left out, for brevity, a join table, because a package may belong to many contracts. The sql here includes the join table. I updated the models also.
Doing joins in in activerecord is quite straight forward as long as you have defined the relationships in your models. You just pass a hash to joins
and it figures out what keys to use. Adding the where conditions can be done in similar fashion.
I noticed that there was no has_many :payments
in your invoice is this by design? In that case why?
The select clause I have written will give all Service objects created with this query an extra method count
where you will find your value.
Service.select('*, count(*) as count')
.joins({
package: {
contract: {
invoices: :payment
}
}
})
.where(conditions_hash)
.group('services.id asc')
.order(:id)
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.