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

时间:2015-02-25 04:23:53

标签: ruby-on-rails ruby-on-rails-4 activerecord

设置

我有一个像这样的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都存在问题。感谢有关如何使这项工作的任何指示。

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

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

问题

如何才能让deposits范围返回的内容实际成为Deposit::ActiveRecord_Association...,以便我可以将Deposit类的范围链接起来?

3 个答案:

答案 0 :(得分:3)

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

我从关键http://pivotallabs.com/merging-scopes-with-sti-models/发现了这篇文章,关于在范围内使用are_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 }

答案 1 :(得分:1)

您可能想说一个帐户has_many :deposits

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

然后你应该能够查询

a.deposits.pending

答案 2 :(得分:1)

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