如何让所有不的用户拥有汽车?
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必须从user_id
表中获取所有cars
,然后发出一个巨大的查询。我知道我可以在SQL中进行子查询,但必须有更好的Rails / ActiveRecord方式。
更新2 :我现在的查询效率明显提升:
includes(:car).where(cars: {id: nil})
我在下面接受的答案是joins
,其中包含SQL字符串而不是includes
。我不知道includes
是否效率更低,因为它将nil
数据存储在Ruby对象中,而joins
可能不存在?我喜欢不使用字符串......
答案 0 :(得分:0)
一种方法是使用从users
表到cars
表的左连接,并仅获取cars
表中没有任何相应值的用户条目,看起来像:
User.select('users.*').joins('LEFT JOIN cars ON users.id = cars.user_id').where('cars.id IS NULL')
答案 1 :(得分:0)
这里需要完成的大部分工作都是SQL。试试这个:
User.joins("LEFT OUTER JOIN cars ON users.id = cars.user_id").where("cars.id IS NULL")
使用ruby执行此操作非常低效,正如您似乎正在尝试的那样。
您也可以在那里下订单:
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
这样很棒。