STI 子类上作用域的未定义方法错误



设置

我有一个这样的性传播感染设置:

class Transaction < ActiveRecord::Base
  belongs_to :account
  scope :deposits, -> { where type: Deposit }
end
class Deposit < Transaction
  scope :pending, -> { where state: :pending }
end
class Account < ActiveRecord::Base
  has_many :transactions
end

如果我打电话:

> a = Account.first
> a.transactions.deposits

。然后我得到了我期望的,一个Deposit实例的集合,但是如果我查看返回的类:

> a.transactions.deposits.class

。那么它实际上不是存款集合,它仍然是一个交易集合,即。这是一个Transaction::ActiveRecord_AssociationRelation

问题所在

因此,对于这个问题,如果我想调用该集合上的Deposit范围之一,它将失败:

> a.transactions.deposits.pending
NoMethodError: undefined method `pending' for #<Transaction::ActiveRecord_Associations_CollectionProxy:0x007f8ac1252d00>

我检查过的东西

我尝试将范围更改为Deposit.where...没有效果,并且更改为实际上返回正确集合对象的Deposit.unscoped.where...但它剥离了所有范围,因此我丢失了查询的account_id=123部分,因此它在那一端失败。

我已经检查过了,Rails 4.1 和 4.2 都存在问题。感谢您有关如何完成这项工作的任何指示。

我知道有一个解决方法,但是...

我知道我可以通过在Account中添加一个has_many :deposits来解决这个问题,但我试图避免这种情况(实际上我有许多关联的表和许多不同的事务子类,我试图避免添加数十个额外的关联需要(。

问题

如何使deposits范围返回的内容实际成为Deposit::ActiveRecord_Association...,以便我可以将范围从类中链接Deposit

我在这里为您的问题创建了一个隔离测试:https://gist.github.com/aalvarado/4ce836699d0ffb8b3782#file-sti_scope-rb 它有你提到的错误。

我从关键 http://pivotallabs.com/merging-scopes-with-sti-models/中看到了这篇文章,内容涉及在范围内使用were_values来获取所有条件。然后我在unscope上使用它们来强制预期的类,基本上是这样的:

  def self.deposits
    conditions = where(nil).where_values.reduce(&:and)
    Deposit.unscoped.where(conditions)
  end

此测试断言它返回一个Deposit::ActiveRecord_Relation https://gist.github.com/aalvarado/4ce836699d0ffb8b3782#file-sti_scope2-rb

更新

如果您愿意,也可以将其编写为范围:

  scope :deposits, -> { Deposit.unscoped.where where(nil).where_values.reduce &:and }

作为一种快速解决方法,您可以执行> a.transactions.deposits.merge(Deposit.pending),但想不出不同的解决方法。我会考虑并尝试更多的选择,如果我发现任何东西,我会回来。

您可能

想说帐户has_many :deposits

class Account < ActiveRecord::Base
  has_many :transactions
  has_many :deposits
end

然后你应该能够查询

a.deposits.pending

最新更新