我有一个像这样的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
类的范围链接起来?
答案 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)
,但无法想出解决问题的不同方法。我会想到并尝试更多的选择,如果我找到任何东西,我会回来。