如何在不加载关联模型的情况下检查 has_one 是否存在

how to check if has_one exists without loading associated model

我有一个简单的has_one关系

class User < ApplicationRecord
  has_one :detail
  has_many :courses
end

class Detail < ApplicationRecord
  belongs_to :user
end

我需要检查用户是否有详细信息。既然我可以做到 User.first.courses.exists? ,令人惊讶的是 User.first.detail.exists? 不起作用。我可以 !User.first.detail.nil? 但我只需要检查用户详细信息是否存在而不加载它非常庞大的细节模型。

在不检索整个关联模型的情况下检查 has_one 关联是否存在的好方法是什么?

您可以使用:User.first.detail.present?

Detail.where(user_id: User.first.id).exists?

如果您只想知道用户是否有详细信息,那么这不会分配 Detail 对象。

要在不访问数据库的情况下检查关联是否已加载,您可以使用:

model.association(:association_name).loaded? 用于 has_one/belongs_to 协会,model.many_things.loaded? 用于 has_many 协会。

正在检查是否已加载 has_one/belongs_to 关联:

user = User.find(1)

user.association(:detail).loaded? # => false

user.detail.id # Does DB request to get Detail

user.association(:detail).loaded? # => true
预加载

预加载让您提前加载数据,因此关联被标记为已加载:

user = User.eager_load(:detail).find(1)
user.detail.loaded? # => true

正在检查 has_many 关联是否已加载

与 has_many 关联,

user = User.find(1)
user.association(:courses).loaded? # => false

user.courses.load # Does DB query to get all users' courses
user.association(:courses).loaded? # => true
执行 .first 或其他一些查询不会总是加载

请记住,它不会在所有情况下都标记为已加载:

user.courses.first.id # Does DB query to get first course ID
user.association(:courses).loaded? # => false (still!)

这是因为当您执行 .first 以提高效率时,它实际上是在执行 SELECT * LIMIT 1 查询。

预加载
user = User.eager_load(:courses).find(1)
user.association(:courses).loaded? # => true

什么时候使用 loaded? 方法?

我能想到的唯一用例是当您不想触发数据库调用但想检查数据是否已经加载并且仅在加载时才对其进行处理。

在我的例子中,我想输出一些数据用于记录目的,但前提是它没有通过调用关联添加额外的数据库查询。