使用在父模型中定义的范围,在其子项内(STI模式)

时间:2012-09-17 14:49:05

标签: ruby ruby-on-rails-3 sti

我使用STI模式实现了一个类层次结构

class A
  scope :aaa, where([someField]:[someValue])
end

class B < A
end

问题在于,当我尝试打电话时:

B.limit(5).aaa
=> SELECT "[table]".* FROM "[table]" WHERE "[table]"."type" IN ('A') AND ([someField] = [someValue]) LIMIT 5

所以我得到了5个类型A的对象,它们满足范围:aaa 但是我需要对type =“B”

的行做同样的事情

有没有办法使用父级的范围,而不是在STI模式的子级中重新划分它?

提前致谢

EDITED

我刚刚和我的朋友讨论过,他向我展示了一件重要的事情。 A不是STI的根类。实际上整个层次结构看起来像

class O < ActiveRecord::Base
end

class A < O
  scope ..... .....
end

class B < A
end

也许原因在于层次结构本身?...

3 个答案:

答案 0 :(得分:2)

这是正确的,这是多级层次结构的结果。

如果您只有一个级别的继承(即A继承自ActiveRecord::Base而不是继承自O),则范围将按预期工作。

一旦有中间类,Rails中的STI并不总是按预期工作。

我不确定这是否是Rails中的错误,或者仅仅因为它无法准确推断出应该做什么。我将不得不研究更多。

您遇到的范围问题只是意外行为的一个示例。另一个例子是查询中间类只会查询它所知道的类类型,除非你特别要求它们,否则它们可能不包括它的所有子类:

有关更多信息,请参阅以下主题,特别是MatthewRudy底部的帖子:https://groups.google.com/forum/#!topic/hkror/iCg3kxXkxnA

如果您仍想使用范围而不是@Atastor建议的类方法,则可以将范围放在O而不是A上。这并不理想,因为范围可能不适用于O的每个子类,但它确实会导致Rails查询type列中的正确类,并且是一种快速的解决方法。 / p>

答案 1 :(得分:1)

我会切换到使用类方法而不是范围,例如在A级

def self.aaa
  A.where([someField]:[someValue])
end 

之后在B级

def self.bbb
  self.aaa.where("type = ?","B")
end

答案 2 :(得分:0)

注意STI中级课程,因为它会影响你正在尝试的范围。

在我的情况下,我有:

class A < ActiveRecord
blabla
end
class B < A
scope :dates, ->(start_date, end_date) { where(:date => start_date..end_date) }
end
class C < B
<call scope_dates>
end
class D < B
<call scope_dates>
end

范围实际上包括C级和D级组合。

所以,如果你在Rails中有STI请将范围放在Base类中,而不是中间类