为什么Rails 3在覆盖范围时不排除'或'条件?

时间:2012-10-18 16:05:48

标签: ruby-on-rails ruby-on-rails-3 activerecord scope arel

在ActiveRecord模型上考虑这些范围:

scope :onsale, where(:sales_state => "onsale")
scope :outdated, where(:sales_state => "outdated")
scope :onsale_or_outdated, where(" sales_state = 'onsale' OR sales_state = 'outdated' ")

为什么Rails知道用:onsale覆盖:outdated,而:onsale覆盖:onsale_or_outdated

我的用例:

我有一个有很多范围的关系对象(假设它是一个已保存的搜索),其中一个是:onsale。我想从此开始建立另一种关系,但这次我希望sales_stateonsaleoutdated

如果我使用relation.onsale_or_outdated,则sales_state不会被覆盖,只会添加新条件。

[...] WHERE "cars"."sales_state" = 'onsale' [...] AND (("cars"."sales_state" = 'onsale' OR "cars"."sales_state" = 'outdated'))

如何在此背景下使用我的'或'条件?

1 个答案:

答案 0 :(得分:1)

  

如果我使用relation.onsale_or_outdated,则不会覆盖sales_state,只会添加新条件。

这就是范围的工作原理。他们追加,而不是取代。如果您有两个互斥的范围,则需要使用其中一个,而不是两个。特殊情况是当您的范围涉及:symbol = <value>语法中的单个字段时。 Rails非常聪明,允许一个范围取消另一个范围。在您的情况下,onsale_or_updated范围只是一个字符串,Rails无法判断涉及哪些字段,因此范围是链接的。

您应该重写范围以使用字段/值而不是一串SQL,因此Rails知道涉及哪些字段。

scope :onsale_or_outdated, where(:sales_state => %w(onsale outdated))

或者,如果您只想使用onsale_or_outdated范围,则可以unscope关系并重新应用范围:

relation.unscoped.onsale_or_outdated

请注意,这将删除以前应用的任何范围。