5

我使用 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 模式在子级中重新定义它?

提前致谢

已编辑

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

class O < ActiveRecord::Base
end

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

class B < A
end

也许原因在于等级制度本身?...

4

3 回答 3

2

You are correct that this is a result of the multi-level hierarchy.

The scope would work as expected if you had just one level of inheritance (i.e. if A inherited from ActiveRecord::Base instead of inheriting from O).

STI in Rails does not always work as expected once you have intermediate classes.

I'm not sure if this is a bug in Rails or just a result of it not being feasible to infer exactly what should be done. I'll have to research that more.

The scope issue you experienced is just one example of the unexpected behavior. Another example is that querying the intermediate class will only query for the class types it is aware of, which may not include all of its subclasses unless you specifically require them:

See the following thread for more information, especially the post at the bottom by MatthewRudy: https://groups.google.com/forum/#!topic/hkror/iCg3kxXkxnA

If you still want to use scopes instead of class methods as suggested by @Atastor, you can put the scope on O instead of A. This isn't ideal since the scope may not be applicable to every subclass of O, but it does seem to cause Rails to query the correct classes in the type column, and is a quick workaround.

于 2012-10-20T16:33:45.070 回答
1

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

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

然后在B级

def self.bbb
  self.aaa.where("type = ?","B")
end
于 2012-09-17T15:36:50.727 回答
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 请将范围放在基类中,而不是中间类

于 2015-02-18T15:17:06.710 回答