0

考虑 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_stateonsaleor outdated

如果我使用relation.onsale_or_outdatedsales_state则不会被覆盖,它只会添加一个新条件。

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

在这种情况下,我如何使用我的“或”-ed 条件?

4

1 回答 1

1

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

这就是作用域的工作原理。它们是附加的,而不是替换的。如果您有两个互斥范围,则需要使用其中一个,而不是同时使用两者。特殊情况是当您的范围涉及:symbol = <value>语法中的单个字段时。Rails 足够聪明,可以让一个作用域抵消另一个作用域。在您的情况下,onsale_or_updated范围只是一个字符串,Rails 无法判断涉及哪些字段,因此范围是链接的。

您应该重写您的范围以使用字段/值而不是 SQL 的 blob,以便 Rails 知道涉及哪些字段。

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

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

relation.unscoped.onsale_or_outdated

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

于 2012-10-18T16:07:12.877 回答