Как правильно настроить 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_{что когда-либо}.

Другие вопросы по тегам