2014-11-07 4 views
0

у меня есть глубоко вложенный макет следующим образом:Rails сложный запрос с несколькими ассоциациями уровня

Контракт -> имеет много пакетов -> есть много услуг

Оплаты -> belongs_to Счета-фактуры -> belongs_to контракта

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 

Я хочу найти, какие услуги и сколько раз выставляли счета в течение определенного периода времени, исходя из даты платежа. Дата выставления счета может не совпадать с датой платежа.

Я знаю, как это сделать с помощью чистого SQL, и это работает, но я застреваю, если я хочу сделать это рельсы.

Любые идеи?

Edit:

Чистый SQL-запрос:

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 

В моем первоначальном вопросе я ушел из, для краткости, таблиц объединения, так как пакет может принадлежать многие контрактам. Здесь sql включает таблицу соединений. Я также обновил модели.

+0

Можете ли вы поместить здесь чистый путь SQL? Это очень поможет. А для записи вы можете конвертировать SQL-запросы в запросы Arel, готовые для Rails с этим сайтом: http://www.scuttle.io/ –

+0

Обновлен вопрос. –

ответ

0

Выполнение подключений в activerecord довольно прямолинейно, если вы определили отношения в своих моделях. Вы просто передаете хэш на joins, и он выясняет, какие ключи использовать. Добавление условий, где условия могут быть выполнены аналогичным образом.

Я заметил, что в вашем счете это не было has_many :payments - это по дизайну? В таком случае почему?

Выбранное предложение, которое я написал, даст всем объектам службы, созданным с этим запросом, дополнительный метод count, где вы найдете свое значение.

Service.select('*, count(*) as count') 
.joins({ 
    package: { 
    contract: { 
     invoices: :payment 
    } 
    } 
}) 
.where(conditions_hash) 
.group('services.id asc') 
.order(:id) 
+0

Спасибо. Я дам ему попробовать. У одного счета есть только один платеж, поэтому у меня нет 'has_many: payments'. –

+0

попробуйте 'has_one: payment', это может повлиять на запрос ... – Albin