Shrine项目ActiveRecord插件深度解析:文件上传与模型集成指南
shrine File Attachment toolkit for Ruby applications 项目地址: https://gitcode.com/gh_mirrors/shr/shrine
前言
在现代Web开发中,文件上传是一个常见需求。Shrine作为一个灵活的文件上传库,提供了与ActiveRecord无缝集成的能力。本文将深入探讨Shrine的ActiveRecord插件,帮助开发者理解如何将文件上传功能优雅地整合到Rails应用中。
插件基础
要启用ActiveRecord集成,只需在Shrine配置中添加以下代码:
Shrine.plugin :activerecord
这个插件建立在model
插件之上,为ActiveRecord模型添加了完整的附件处理能力。
模型附件集成
基本用法
在ActiveRecord模型中集成Shrine附件非常简单:
class Photo < ActiveRecord::Base # 假设有image_data列
include ImageUploader::Attachment(:image) # 添加方法、回调和验证
end
这种集成方式为模型添加了完整的附件生命周期管理:
photo = Photo.new
# 缓存附件
photo.image = file
# 访问附件
photo.image #=> #<Shrine::UploadedFile id="bc2e13.jpg" storage=:cache ...>
photo.image_data #=> '{"id":"bc2e13.jpg","storage":"cache","metadata":{...}}'
# 持久化:提升附件并再次持久化
photo.save
# 附件已提升到永久存储
photo.image #=> #<Shrine::UploadedFile id="397eca.jpg" storage=:store ...>
photo.image_data #=> '{"id":"397eca.jpg","storage":"store","metadata":{...}}'
# 删除记录时同时删除附件
photo.destroy
# 验证附件是否存在
photo.image.exists? #=> false
回调机制
保存后回调
当记录被保存且事务提交后,会触发Attacher#finalize
方法,该方法负责:
- 将缓存文件提升到永久存储
- 删除之前的文件(如果有)
photo = Photo.new
photo.image = file
photo.image.storage_key #=> :cache
photo.save
photo.image.storage_key #=> :store
销毁后回调
记录被销毁且事务提交后,会调用Attacher#destroy_attached
方法删除关联的存储文件。
photo = Photo.find(photo_id)
photo.image.exists? #=> true
photo.destroy
photo.image.exists? #=> false
回调注意事项
-
执行顺序:ActiveRecord存在一个已知的事务回调bug,因此确保在定义完所有"after commit"回调后再引入Shrine的附件模块。
-
自定义回调:可以覆盖以下方法来修改回调行为:
Attacher#activerecord_before_save
Attacher#activerecord_after_save
Attacher#activerecord_after_destroy
class Shrine::Attacher
def activerecord_after_save
super
# 自定义逻辑
end
end
- 禁用回调:如果不希望添加任何回调,可以配置:
plugin :activerecord, callbacks: false
验证集成
当使用validation
插件时,附件模块会自动将验证错误合并到模型错误中。
基本验证
class ImageUploader < Shrine
plugin :validation_helpers
Attacher.validate do
validate_max_size 10 * 1024 * 1024
end
end
photo = Photo.new
photo.image = file
photo.valid?
photo.errors #=> { image: ["size must not be greater than 10.0 MB"] }
附件存在性验证
使用ActiveRecord的原生验证器:
class Photo < ActiveRecord::Base
include ImageUploader::Attachment(:image)
validates_presence_of :image
end
国际化支持
Shrine支持ActiveRecord的错误消息国际化:
class ImageUploader < Shrine
plugin :validation_helpers
Attacher.validate do
validate_max_size 10 * 1024 * 1024, message: -> (max) { [:too_large, max: max] }
validate_mime_type %w[image/jpeg image/png], message: :not_image
end
end
对应的国际化文件配置:
en:
activerecord:
errors:
models:
photo:
attributes:
image:
too_large: "must not be larger than %{max} bytes"
not_image: "must be a common image format"
禁用验证
plugin :activerecord, validations: false
直接使用Attacher
除了通过Shrine::Attachment
模块,也可以直接使用Shrine::Attacher
:
class Photo < ActiveRecord::Base # 有image_data列
end
photo = Photo.new
attacher = ImageUploader::Attacher.from_model(photo, :image)
attacher.assign(file) # 缓存
attacher.file #=> #<Shrine::UploadedFile id="bc2e13.jpg" storage=:cache ...>
photo.image_data #=> '{"id":"bc2e13.jpg","storage":"cache","metadata":{...}}'
photo.save # 持久化
attacher.finalize # 提升
photo.save # 再次持久化
attacher.file #=> #<Shrine::UploadedFile id="397eca.jpg" storage=:store ...>
photo.image_data #=> '{"id":"397eca.jpg","storage":"store","metadata":{...}}'
持久化方法
Shrine::Attacher
添加了以下持久化方法:
| 方法 | 描述 | | :----- | :---------- | | atomic_promote
| 提升附件并在附件未更改时持久化 | | atomic_persist
| 在附件未更改时保存变更 | | persist
| 将任何变更保存到底层记录 |
最佳实践
- 事务安全:所有文件操作都在数据库事务完成后执行,确保数据一致性
- 错误处理:合理处理验证错误,提供用户友好的反馈
- 性能考虑:大文件上传时考虑使用后台任务处理文件提升操作
- 测试策略:同时测试模型和附件的交互,确保回调按预期工作
通过合理配置Shrine的ActiveRecord插件,开发者可以轻松实现强大而灵活的文件上传功能,同时保持代码的整洁和可维护性。
shrine File Attachment toolkit for Ruby applications 项目地址: https://gitcode.com/gh_mirrors/shr/shrine
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考