0

我遇到了 activerecord 关系的有趣行为。

class A < ActiveRecord::Base
  def self.one
    where("1=1")
  end

  def self.two
    puts A.where("2=2").to_sql
  end

  def self.test
     one.two
  end
end
A.test # prints  ... WHERE 1=1 AND 2=2

我预计 Ad.where("2=2") 在 self.two 中不包含“1=1”,但确实如此。是特色吗?

4

1 回答 1

2

是的,这是一个功能。

传递给的所有值where都由关系 ( @values[:where]) 内部存储,并与 AND 连接以构建 WHERE 语句。

two在返回的关系的上下文中调用时one,one 存储的“where 值”用作构建新范围的基础。

您可以使用以下方法获得所需的行为unscoped

one.unscoped.two

编辑:是的,这显然很奇怪且违反直觉。

我刚遇到和你一样的问题。

经过大量挖掘,似乎从 rails 4 开始,所有模型都保留了一个线程本地注册表,用于存储该类/关系上使用的当前范围。我不知道他们为什么这样做,我猜这与性能有关

关键是,当您已经链接了一堆范围并尝试调用另一个引用该类的范围(如two您的示例中)时,ActiveRecord 只会获取该类的当前范围 - 即您调用的关系范围放在首位!很傻。事实上,你的two方法可以在没有A类引用的情况下被重写,它不会改变任何东西。

更奇怪的是,使用 STI 时出现了另一个问题:在我的范围内,我使用pluck. 不仅这个“功能”以意想不到的方式影响了查询,而且似乎它还“重置”了默认范围,因此下一个查询(这是范围的实际返回)“忘记”了之前传递的所有条件范围... WTF?

结论:我认为我们应该在 Rails github 上开一张票,至少要求团队记录这种奇怪的行为。(MyClass.unscoped在我的第一个查询中使用解决了我的问题,但不直观)

于 2013-10-24T12:10:27.357 回答