Rails 未附加文件时的 ActiveStorage 范围

Rails ActiveStorage scope for when file is NOT attached

使用 ActiveStorage 时,如何为未附加文件创建范围。

例如:

class Check < ActiveRecord::Base
  has_one_attached :image
end

我想要 Check.has_no_attached_image 之类的东西 return 只记录没有现有附加图像的地方。

找到了一个 附上图片而不是相反的情况
scope :has_attached_image, -> { joins(image_attachment: :blob) }

您可以使用 left_joins 和关联名称(图像 + _attachment)来实现,它被解释为:

SELECT users.*
FROM users LEFT OUTER JOIN active_storage_attachments
ON active_storage_attachments.record_id = users.id
AND active_storage_attachments.record_type = 'User'
AND active_storage_attachments.name = 'image'

然后应用 WHERE 过滤器以获取那些与 active_storage_attachments table:

不匹配的用户行
User.left_joins(:image_attachment).where(active_storage_attachments: { id: nil })

我只是想补充这个答案,因为上面的答案对我不起作用(可能是因为我使用的是 Rails 6?不确定)。以下是对我有用的方法:

scope :without_attached_image, -> { left_joins(:image_attachment).where('active_storage_attachments.id IS NULL') }

在 Rails 6.1 中,添加了 where.missing 功能,导致:

Check.where.missing(:image_attachment)

可以确认 missing 在 6.1 中有效。

这里有一些有用的通用范围,包括许多情况。

不幸的是,rails 中没有内置的复数检查,所以针对单例和多例的范围是分开的

  has_one_attached :file
  has_many_attached :documents

  scope :with_attachment, ->(name) { joins(:"#{name}_attachment") }
  scope :with_attachments, ->(name) { joins(:"#{name}_attachments") }
  scope :without_attachment, ->(name) { where.missing(:"#{name}_attachment") }
  scope :without_attachments, ->(name) { where.missing(:"#{name}_attachments") }

  TestModel.with_attachment(:file)
  TestModel.with_attachments(:documents)
  TestModel.without_attachment(:file)
  TestModel.without_attachments(:documents)