如何为User模型编写Scope,筛选所有关联Document均含附件的用户?
问题描述
假设存在User和Document模型,关联关系为:
User has_many :documentsDocument belongs_to :user
Document模型包含has_one_attached :file字段用于关联附件,且已在Document.rb中定义两个Scope:
scope :without_attached_file, -> { where.missing(:file_blob) } scope :with_attached_file, -> { where.associated(:file_blob) }
需要为User模型编写一个Scope,筛选所有关联的Document记录全部绑定了file附件的用户实例。例如:某用户关联10条Document且全部带附件,则该用户应被包含在此Scope中。
用户尝试了以下Scope,但仅返回关联带附件Document的数量,无法满足需求:
scope :with_attached_files_for_all_documents, -> { joins(documents: :file_attachment) .group('users.id') .having("COUNT(documents.id) = COUNT(CASE WHEN active_storage_attachments.record_type = 'Document' THEN documents.id ELSE NULL END)") }
解决方案
方法1:反向筛选(排除存在无附件文档的用户)
最直接的思路是:筛选没有任何关联文档缺失附件的用户,也就是排除那些关联了without_attached_file文档的用户。
简洁子查询写法
scope :all_documents_have_attached_file, -> { where.not(id: Document.without_attached_file.select(:user_id)) }
逻辑:先找出所有存在无附件文档的用户ID,排除这些用户后,剩下的就是所有文档都带附件的用户(默认包含无任何文档的用户)。
若需排除无文档的用户
scope :all_documents_have_attached_file, -> { where.not(id: Document.without_attached_file.select(:user_id)) .joins(:documents) .distinct }
方法2:分组统计对比总数与带附件数
通过分组用户ID,统计每个用户的总文档数和带附件的文档数,当两者相等时,说明所有文档都带附件:
scope :all_documents_have_attached_file, -> { joins(:documents) .group('users.id') .having('COUNT(documents.id) = COUNT(documents.file_blob_id)') }
原理:file_blob_id是Active Storage关联的外键,无附件的文档该字段为NULL,COUNT(documents.file_blob_id)只会统计非NULL的记录(即带附件的文档数),与总文档数对比即可判断是否全部带附件。
方法3:复用已有Document Scope
结合已定义的without_attached_file,通过反向exists逻辑实现,可读性更强:
scope :all_documents_have_attached_file, -> { where.not( Document.without_attached_file.where('documents.user_id = users.id').exists ) }
内容的提问来源于stack exchange,提问作者pinkfloyd90
相关产品推荐
相关产品推荐

