轨道上的红宝石 - 针对没有汽车的用户的活动记录查询



如何获得所有没有汽车的用户?

class User < ActiveRecord::Base
  has_one :car
end
class Car < ActiveRecord::Base
  belongs_to :user
end

我正在执行以下操作:

all.select {|user| not user.car }

这很完美,直到我的用户和汽车数据库变得太大,现在我得到奇怪的错误,尤其是当我尝试对结果进行排序时。我需要在查询和排序以及查询的一部分中进行过滤。

更新:我所做的是以下内容:

where('id not in (?)', Car.pluck(:user_id)).order('first_name, last_name, middle_name')

它相当慢,因为Rails必须从cars表中获取所有user_id,然后发出一个巨大的查询。我知道我可以在SQL中做一个子查询,但必须有一个更好的Rails/ActiveRecord方法。

更新2:我现在有一个明显更有效的查询:

includes(:car).where(cars: {id: nil})

我在下面接受的答案是用SQL字符串而不是includes joins。我不知道includes是否效率更低,因为它将nil数据存储在 Ruby 对象中,而joins可能没有?我喜欢不使用字符串...

一种方法

是使用从users表到cars表的左连接,并且只接受cars表中没有任何相应值的用户条目,如下所示:

User.select('users.*').joins('LEFT JOIN cars ON users.id = cars.user_id').where('cars.id IS NULL')

这里需要完成的大部分工作都是SQL。 试试这个:

User.joins("LEFT OUTER JOIN cars ON users.id = cars.user_id").where("cars.id IS NULL")

用红宝石做到这一点是非常低效的,正如你似乎试图做的那样。

您也可以在那里下订单:

User.
  joins("LEFT OUTER JOIN cars ON users.id = cars.user_id").
  where("cars.id IS NULL").
  order(:first_name, :last_name, :middle_name)

您可以将其作为User模型的范围,以便只有一个位置来处理它:

class User < ActiveRecord::Base
  has_one :car
  def self.without_cars
    joins("LEFT OUTER JOIN cars ON users.id = cars.user_id").
    where("cars.id IS NULL").
    order(:first_name, :last_name, :middle_name)
  end
end

这样,您可以执行以下操作:

User.without_cars

在您的控制器或其他方法中,甚至链接范围:

User.without_cars.where("users.birthday > ?", 18.years.ago)

查找没有 18 岁以下汽车的用户(任意示例,但你明白了)。 我的观点是,这种东西应该始终被制作成一个作用域,这样它就可以与其他作用域链接起来:) Arel这样真棒。

相关内容

  • 没有找到相关文章

最新更新