设置

我有一个像这样的 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 类链接我的范围?

最佳答案

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

我从关键的 http://pivotallabs.com/merging-scopes-with-sti-models/ 看到这篇关于在范围内使用 was_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 }

关于ruby-on-rails - STI 子类范围的未定义方法错误,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/28711074/

10-11 07:56