【问题标题】:How do I make named_scope work properly with a joined table?如何使 named_scope 与连接表一起正常工作?
【发布时间】:2009-09-24 06:57:43
【问题描述】:

这是我的情况。我有两个表:承诺和承诺交易。当用户做出承诺时,他在承诺表中只有一行。

稍后到了履行承诺的时候,每笔付款都会记录在我的承诺交易表中。

我需要能够查询所有未结的质押,这意味着交易表中的金额总和小于质押金额。

这是我目前所拥有的:

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 确认条件中的质押交易表时,它会完全省略它,这意味着我的 having 子句变得毫无意义。

我认为我遇到了 ActiveRecord 的缺点。

最终我需要能够做到以下几点:

  • Pledge.open
  • Pledge.open.count
  • Pledge.open.find(:all, ...)

有人对这个问题有更优雅的答案吗?请不要建议每次交易发生时增加一个承诺 amount_given 字段。这感觉像是一种创可贴的方法,我更喜欢在创建承诺后保持不变并计算差异。

如果我在这里不使用 Rails,我只会创建一个视图并完成它。

谢谢!

【问题讨论】:

    标签: ruby-on-rails ruby activerecord named-scope


    【解决方案1】:

    :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
    

    我认为书籍/文档并没有过多介绍,因为不同平台的视图实现和支持差异很大。

    【讨论】:

      【解决方案2】:

      我认为在你的条件下使用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_{whatever}。

      【讨论】:

      • 詹姆斯,非常有趣的想法。然而,需要考虑的一件事是,这个系统中的一个人可以对他们的质押进行部分支付,他们的质押仍然被认为是开放的。这就是为什么我一直在用 sum() 来解决这个问题。如果质押的总和不等于或大于质押,质押仍被视为未完成(未履行)。
      • 嘿 rwl4,你仍然可以使用 NOT EXISTS 子句,我已经添加了数量
      猜你喜欢
      • 2012-07-02
      • 2020-06-09
      • 2014-09-09
      • 2021-03-14
      • 1970-01-01
      • 2020-10-24
      • 2019-03-08
      • 2019-12-30
      • 1970-01-01
      相关资源
      最近更新 更多