Rails 类方法作用域进行额外的查询



我有两个对象之间的关系。让我们这样说:模型 1 has_many模型 2(这并不重要)

然后说,我想过滤掉一些结果:

a = Model1.find(123) 
b = a.model2

现在,例如,我只想选择偶数记录(按 ID)

如果我执行以下操作:b.select {|x| x.id % 2 == 0}那么它会按预期返回所有偶数记录。并且没有创建其他数据库查询。

但是如果我在 Model2 中定义一个类方法:

def self.even_records
   select {|x| x.id % 2 == 0}
end

然后,出于某种神奇的原因,它对数据库进行了额外的查询,看起来它重新实例化了"b"变量(重新加载关系):

Model2 Load (0.4ms)  SELECT `model2`.* FROM `model2` WHERE `model2`.`model1_id` = 123

为什么它表现得如此?有什么方法可以解决吗?

附言我没有可疑的回调,例如after_find或任何模型中定义的回调。

ActiveRecord作用

域被惰性地计算,即当需要其结果时,作用域被计算。在控制台中尝试此代码时,inspect方法将在每个评估对象上隐式调用,包括从 返回ActiveRecord::Relation实例

b = a.model2

叫。在ActiveRecord::Relation上调用inspect后,将评估范围并创建数据库查询,因为有必要正确显示inspect返回值。

相反,当您在 rails 控制台之外运行代码时,

b = a.model2

不会生成数据库查询,因此可能只有一个数据库查询。

这两者之间的基本区别在于,当您在数组 b 上调用 select 方法时,它调用可枚举方法 select。

b.select {|x| x.id % 2 == 0} 

当你在方法中编写时,它会调用 Select 方法的 ActiveRecord 查询接口。

def self.even_records
   select {|x| x.id % 2 == 0}
end

顺便说一句,Ruby 有像 even?odd? 这样的方法,所以你可以直接调用它们:

even_records = b.select{|x| x.id.even?}
odd_records = b.select{|x| x.id.odd? }

Edit:我为您找到了一个简单的解决方案,您可以在模型中定义一个范围,Model2如下所示,

scope :even_records, -> { where ('id % 2 == 0') }

现在,如果您将致电:

Model2.even_records

你会有你的even_records。谢谢

相关内容

  • 没有找到相关文章

最新更新