如何查询具有 ActiveStorage 附件的记录?

How to query records that have an ActiveStorage attachment?

给定一个带有 ActiveStorage 的模型

class User 
  has_one_attached :avatar
end

我可以查看单个用户是否有头像

@user.avatar.attached? 

但是我如何才能 return 包含所有带(或所有不带)附件的用户的集合?

我尝试使用 joins 来 return 所有有附件的用户,但这似乎对 blob 或附件 table 不起作用,或者我可能没有让语法正确。

我确定我忽略了一些显而易见的事情。是否可以按照以下方式做一些事情:

User.where(attached_avatar: nil)

如果是这样,记录在哪里?

附件关联名称约定

附件关联使用以下约定命名:

<NAME OF ATTACHMENT>_attachment

例如,如果您有 has_one_attached :avatar,则关联名称将为 avatar_attachment

正在查询活动存储附件

现在您知道附件关联是如何命名的,您可以像查询任何其他 Active Record 关联一样使用 joins 查询它们。

例如,给定下面的 User class

class User
   has_one_attached :avatar
end

您可以查询具有该附件的所有User记录,如下所示

User.joins(:avatar_attachment)

这会执行一个 INNER JOIN,它只会 return 有附件的记录。

您可以像这样查询所有 User 没有该附件的记录

User.
  left_joins(:avatar_attachment).
  group(:id).
  having("COUNT(active_storage_attachments) = 0")

有点相关,这里是如何对附加记录执行搜索查询:

def self.search_name(search)
  with_attached_attachment.
    references(:attachment_attachment).
    where(ActiveStorage::Blob.arel_table[:filename].matches("%#{search}%"))
end

您只需更新 with_attached_attachment:attachment_attachment 以反映您附加的模型。就我而言,我有 has_one_attached :attachment

对于那些想知道的人,Arel #matches 似乎不容易受到 SQL 注入攻击。

我想知道记录是否有任何附件(我有多个附件,比如 User 的护照和其他文件)所以我可以 display/hide UI 中的一个部分。

根据答案 我已经能够将以下方法添加到 ApplicationRecord:

def any_attached?
  ActiveStorage::Attachment.where(record_type: model_name.to_s, record_id: id).any?
end

然后你可以像这样使用它:

User.last.any_attached?
#=> true

查询带有附件的记录:

User.joins(:avatar_attachment)

不带附件的查询记录:

User.includes(:avatar_attachment).where(avatar_attachment: {id: nil})