Как правильно настроить named_scope для объединенной таблицы?
Вот моя ситуация. У меня есть две таблицы: pledges и pledge_transactions. Когда пользователь вносит залог, у него есть только строка в таблице залогов.
Позже, когда приходит время выполнить обещание, каждый платеж регистрируется в моей таблице pledge_transactions.
Мне нужно иметь возможность запрашивать все открытые залоги, что означает, что сумма сумм в таблице транзакций меньше, чем объявленная сумма.
Вот что у меня так далеко:
named_scope :open,
:group => 'pledges.id',
:include => :transactions,
:select => 'pledge_transactions.*',
:conditions => 'pledge_transactions.id is not null or pledge_transactions.id is null',
:having => 'sum(pledge_transactions.amount) < pledges.amount or sum(pledge_transactions.amount) is null'
Вы можете спросить себя, почему у меня указана эта лишняя и нелепая опция условий. Ответ заключается в том, что, когда я не заставляю ActiveRecord подтвердить таблицу pledge_transactions в условиях, она полностью ее пропускает, а это означает, что мое предложение о наличии становится бессмысленным.
Я считаю, что я столкнулся с недостатком ActiveRecord.
В конечном итоге мне нужно сделать следующее:
- Pledge.open
- Pledge.open.count
- Pledge.open.find (: все, ...)
- и т.п.
У кого-нибудь есть более элегантный ответ на эту проблему? Пожалуйста, не предлагайте увеличивать значение поля обещания каждый раз, когда происходит транзакция. Это похоже на бандитский подход, и я гораздо больше поддерживаю сохранение статичности залога после его создания и вычисление разницы.
Если бы я не использовал здесь Rails, я бы просто создал представление и покончил с этим.
Спасибо!
2 ответа
Как :transactions
ассоциация определена? Предусматривает ли это :class_name = 'PledgeTransaction'
(или какой бы ни был класс, если он использует set_table_name
)?
Вы смотрели на :joins
параметр? Я думаю, что это может быть то, что вы искали. Конечно, это :conditions
вещь не выглядит правильно.
Если бы я не использовал здесь Rails, я бы просто создал представление и покончил с этим
То, что это Rails, не означает, что вы не можете использовать представление. Хорошо, в зависимости от того, как он сконструирован, вы не сможете его обновить, но в противном случае сделайте это. Вы также можете создавать и удалять представления в миграциях:
class CreateReallyUsefulView < ActiveRecord::Migration
def self.up
# this is Oracle, I don't know if CREATE OR REPLACE is widely-supported
sql = %{
CREATE OR REPLACE VIEW really_usefuls AS
SELECT
... blah blah SQL blah
}
execute sql
end
def self.down
execute 'drop view really_usefuls'
end
end
class ReallyUseful < ActiveRecord::Base
# all the usual stuff here, considering overriding the C, U and D parts
# of CRUD if it's supposed to be read-only and you're paranoid
end
Я думаю, что книги / документы не вдавались в подробности, потому что реализация и поддержка представлений значительно различаются на разных платформах.
Я думаю, используя NOT EXISTS
в ваших условиях вы получите то, что хотите. Я предполагаю, что ассоциация на pledge_transaction
как pledge_id
, Вот как бы я реализовал #open
named_scope :open,
:conditions =>
"
NOT EXISTS (
select 1
from pledge_transactions
where
pledge.id = pledge_transactions.pledge_id AND
pledge_transactions.amount < pledge.amount
)
"
}
}
Это позволит вам сделать Pledge.open, Pledge.open.count и Pledge.open.find_by_{что когда-либо}.