一篇超水的 Rails ActiveStorage 源码解读(后端部分)
ActiveStorage 是 Rails 5.2 的一个新特性 ,建议你先去读完官方的文档再回看来这个
https://guides.rubyonrails.org/active_storage_overview.html
1 | ▾ activestorage-5.2.1/ |
数据结构
先看 db/migrate/20170806125915_create_active_storage_tables.rb
我们能看到两张表,其中一张表储存的是文件信息。。en,en 文件的基本信息
另一张表是储存文件的对象信息
active_storage_blobs
这个表储存了所有文件的基本信息,我们可以看到这个表只有 created_at
,因为这张表被设计成只能添加和删除。
key
是文件唯一的索引。 Disk service
默认把文件放在 storage 目录下,然后建立了以key
值开头两位命名的两个目录。。。。有点绕)
就像这样,来解决大量文件的查找问题:storage/qS/gY/qSgYgMNvwQNzpvBsx91QHQwW
1 | rsd_development=# SELECT * FROM active_storage_blobs; |
active_storage_attachments
1 | rsd_development=# SELECT * FROM active_storage_attachments; |
这张表是通过对象名
和属性名
和对象id
来绑定文件的。。。如果你改了。类名。。那就呵呵了
不同的attachments
是可以指定同一个blobs
的,但是更新blobs
只有一个会更新(应该是删了重建)。。。
这里应该算个坑 blobs
在删除时并不会检测attachments
里是否有包含这个blobs
(我不知道他为什么这么实现啊。喵) 咱觉得这应该算 bug。。。或者每次检查开销太大?留给开发者自己解决?
云存储 lib/active_storage/service/
这里面除了 local
和 mirrors
默认还集成了 Amazon S3 Service, Microsoft Azure Storage Service,Google Cloud Storage Service 服务,当然还要引入对应的SDK
active_storage 和 active_job 一样,只是提供一个中间层。具体还要引入对应云服务的sdk
大概是这样:
active_storage -> active_storage_
国内的可以用 upyun, qiniu, aliyun 都有 gem 可以直接用
attached 附件
这里面有三个文件,有个叫macros
值得一看,在注释里说了关于 has_one_attached
和 has_many_attached
的 N+1 查询问题的解决办法
我来抄段源码:
1 | class User < ActiveRecord::Base |
# There is no column defined on the model side, Active Storage takes
# care of the mapping between your records and the attachment.
#
# To avoid N+1 queries, you can include the attached blobs in your query like so:
1 | User.with_attached_avatar |
1 | class Gallery < ActiveRecord::Base |
# There are no columns defined on the model side, Active Storage takes
# care of the mapping between your records and the attachments.
#
# To avoid N+1 queries, you can include the attached blobs in your query like so:
1 | Gallery.where(user: Current.user).with_attached_photos |
其他
然后就是一些分析啊,预览啊之类的功能。。。没啥说的。。。
activestorage 文件存储的理解
activestorage
把 Disk service
也当作云盘来处理,因此不会有 .path
之类的获取路径的方法。所有的获取文件都是通过.download
方法来实现的,如果要传路径,就先存在一个 tmp 的目录中
还有我觉得官方的文档 .download
的那个方法的用法太有误导性。只要在 rails 获取文件对象就要用.download
来获取 (我当时以为是用户给 url, 然后后台下载。。。。)
后端部分可以拿出来单独用。。。前端部分我还没仔细研究。。不清楚。。。但是他的开发者发了 npm 的包。前后端分离项目用 activestorage 好像也不是什么难事。。enen。大概不是很难