如何阻止Rails 6测试删除操作删除Active Storage的fixture附件文件
解决方案
针对Rails 6 + RSpec栈下事务测试时Active Storage fixture文件被永久删除的问题,有两种可落地的解决方案,无需修改业务逻辑:
方案1:禁用测试环境下Active Storage的实际文件删除逻辑
该方案适合不需要验证文件是否被实际删除的测试场景,零侵入业务代码:
在config/initializers/active_storage.rb中添加以下代码:
if Rails.env.test? # 覆写磁盘存储服务的删除方法,测试环境下不实际删除本地文件 ActiveStorage::Service::DiskService.class_eval do def delete(key) end def delete_prefixed(prefix) end end end
修改后Active Storage的purge操作只会操作数据库记录,不会修改本地文件系统,事务回滚后数据库记录恢复,原文件也保留在存储目录中,不影响后续测试运行。
方案2:通过RSpec钩子每次测试前恢复fixture附件文件
该方案适合需要验证文件删除逻辑是否正常执行的测试场景:
- 提前将fixture关联的所有静态附件文件,按照blob key对应的目录结构,存放在
spec/fixtures/files/active_storage_fixtures目录下 - 在
spec/rails_helper.rb中添加全局钩子,每次测试前将静态文件复制到测试存储目录:
RSpec.configure do |config| # 单测运行前恢复所有fixture附件文件 config.before(:each) do fixture_attachment_dir = Rails.root.join('spec', 'fixtures', 'files', 'active_storage_fixtures') test_storage_dir = Rails.root.join('tmp', 'storage') # Rails测试环境默认Active Storage存储路径 FileUtils.rm_rf(Dir.glob("#{test_storage_dir}/*")) FileUtils.cp_r(Dir.glob("#{fixture_attachment_dir}/*"), test_storage_dir) end # 若使用purge_later异步删除,需开启Active Job inline执行 config.before(:each) do ActiveJob::Base.queue_adapter = :inline end end
注意事项
- 若你的Active Storage测试存储路径做了自定义修改,需要对应调整上述代码中的
test_storage_dir路径 - Fixture中blob记录的key需要和静态文件的存储路径一一对应,比如key为
2fxqd3nfi7sdf89jwk2sdf的文件,存放路径应为ab/cd/2fxqd3nfi7sdf89jwk2sdf,前两位字符拆分为两级子目录
内容的提问来源于stack exchange,提问作者ChrisCPO
相关产品推荐
相关产品推荐

