如何通过Rails Active Storage Blob文件名查询关联模型?
Rails Active Storage Blob文件名查询及关联快捷方式
一、直接查询Blob记录
直接针对ActiveStorage::Blob表操作,利用filename字段做匹配:
- 精确匹配:
ActiveStorage::Blob.where(filename: "example.jpg") - 模糊匹配(包含指定字符串):
ActiveStorage::Blob.where("filename LIKE ?", "%example%") - Arel语法匹配(更安全的SQL构造):
ActiveStorage::Blob.where(ActiveStorage::Blob.arel_table[:filename].matches("%example%"))
二、通过关联模型查询
假设存在Post模型,关联定义如下:
class Post < ApplicationRecord has_one_attached :cover_image has_many_attached :photos end
1. has_one_attached关联查询
查找封面文件名为cover.jpg的Post:
Post.joins(cover_image_attachment: :blob).where(active_storage_blobs: { filename: "cover.jpg" })
这里cover_image_attachment是Rails自动生成的关联别名,无需手动拼接表名。
2. has_many_attached关联查询
查找包含文件名photo1.jpg的Post(需加distinct避免重复返回同一实例):
Post.joins(photos_attachments: :blob).where(active_storage_blobs: { filename: "photo1.jpg" }).distinct
3. 模糊匹配关联附件文件名
查找封面文件名包含cover的Post:
Post.joins(cover_image_attachment: :blob).where("active_storage_blobs.filename LIKE ?", "%cover%")
三、不太显眼的关联查询快捷方式
1. 模型内封装Scope
在模型中定义可复用的查询逻辑,简化调用:
class Post < ApplicationRecord has_one_attached :cover_image has_many_attached :photos scope :with_cover_filename, ->(filename) { joins(cover_image_attachment: :blob).where(active_storage_blobs: { filename: filename }) } scope :with_photo_filename_like, ->(pattern) { joins(photos_attachments: :blob).where("active_storage_blobs.filename LIKE ?", "%#{pattern}%").distinct } end
使用示例:Post.with_cover_filename("cover.jpg")
2. 反向关联查询
从Attachment表反向查询关联的父模型:
# 找到所有关联了文件名"doc.pdf"的文档附件的Post ActiveStorage::Attachment.where(name: :document).joins(:blob).where(active_storage_blobs: { filename: "doc.pdf" }).map(&:record)
record属性直接返回附件所属的父模型实例。
3. 快速判断存在性
检查是否存在封面为指定文件名的Post:
Post.joins(cover_image_attachment: :blob).exists?(active_storage_blobs: { filename: "cover.jpg" })
4. 大小写不敏感匹配
针对不同数据库实现大小写无关的文件名查询:
# PostgreSQL Post.joins(cover_image_attachment: :blob).where("lower(active_storage_blobs.filename) = ?", "cover.jpg".downcase) # MySQL Post.joins(cover_image_attachment: :blob).where("binary lower(active_storage_blobs.filename) = ?", "cover.jpg".downcase) # Arel通用写法 blob_table = ActiveStorage::Blob.arel_table Post.joins(cover_image_attachment: :blob).where(blob_table[:filename].lower.eq("cover.jpg".downcase))
四、注意事项
ActiveStorage::Blob的filename在数据库中存储为字符串,直接用字符串查询有效;- 使用
has_many_attached关联查询时,必须加distinct避免重复返回同一模型实例; - 频繁按文件名查询时,建议给
active_storage_blobs表的filename字段添加索引,提升性能。
内容的提问来源于stack exchange,提问作者Blair Anderson
相关产品推荐
相关产品推荐

