如何获得所有没有汽车的用户?
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
这样真棒。