根据Rails (edge
6.0
)指南,我们可以通过分别调用以下语句来对系统测试和集成测试中使用的ActiveStorage进行维护工作
# System Test
FileUtils.rm_rf("#{Rails.root}/storage_test")
# Integration Test
FileUtils.rm_rf(Rails.root.join('tmp', 'storage'))
我想知道-
Rails 是否有任何内置函数或 rake 命令或 gem 可以执行以下操作?
ActiveStorage::Blob
记录不再与任何 ActiveStorage::Attachment
记录关联)ActiveStorage::Blob
记录关联的文件)我没有看到任何与
rails --tasks
相关的 rake 任务。
目前我正在使用
# remove blob not associated with any attachment
ActiveStorage::Blob.where.not(id: ActiveStorage::Attachment.select(:blob_id)).find_each do |blob|
blob.purge # or purge_later
end
这个脚本用于清理孤立文件(通过
rails console
)
# run these ruby statement in project rails console
# to remove the orphan file
include ActionView::Helpers::NumberHelper
dry_run = true
files = Dir['storage/??/??/*']
orphan = files.select do |f|
!ActiveStorage::Blob.exists?(key: File.basename(f))
end
sum = 0
orphan.each do |f|
sum += File.size(f)
FileUtils.remove(f) unless dry_run
end
puts "Size: #{number_to_human_size(sum)}"
ActiveStorage::Blob.unattached.each(&:purge_later)
或者只是
purge
(如果您不希望它在后台发生)。
我认为问题本身中@Tun 建议的解决方案工作正常。我将其写在 Rake Tasks 版本中,以防为下一个人节省一些时间:
# Usage:
# - rake "remove_orphan_blobs"
# - rake "remove_orphan_blobs[false]"
desc "Remove blobs not associated with any attachment"
task :remove_orphan_blobs, [:dry_run] => :environment do |_t, args|
dry_run = true unless args.dry_run == "false"
puts("[#{Time.now}] Running remove_orphan_blobs :: INI#{" (dry_run activated)" if dry_run}")
ActiveStorage::Blob.where.not(id: ActiveStorage::Attachment.select(:blob_id)).find_each do |blob|
puts("Deleting Blob: #{ActiveStorage::Blob.service.path_for(blob.key)}#{" (dry_run activated)" if dry_run}")
blob.purge unless dry_run
end
puts("[#{Time.now}] Running remove_orphan_blobs :: END#{" (dry_run activated)" if dry_run}")
end
# Usage:
# - rake "remove_orphan_files"
# - rake "remove_orphan_files[false]"
desc "Remove files not associated with any blob"
task :remove_orphan_files, [:dry_run] => :environment do |_t, args|
include ActionView::Helpers::NumberHelper
dry_run = true unless args.dry_run == "false"
puts("[#{Time.now}] Running remove_orphan_files :: INI#{" (dry_run activated)" if dry_run}")
files = Dir["storage/??/??/*"]
orphan_files = files.select do |file|
!ActiveStorage::Blob.exists?(key: File.basename(file))
end
sum = 0
orphan_files.each do |file|
puts("Deleting File: #{file}#{" (dry_run activated)" if dry_run}")
sum += File.size(file)
FileUtils.remove(file) unless dry_run
end
puts "Size Liberated: #{number_to_human_size(sum)}#{" (dry_run activated)" if dry_run}"
puts("[#{Time.now}] Running remove_orphan_files :: END#{" (dry_run activated)" if dry_run}")
end
现在有一种更简单的方法,不确定它何时改变,但有一个警告(它会留下空文件夹):
# rails < 6.1
ActiveStorage::Blob.left_joins(:attachments).where(active_storage_attachments: { id: nil }).find_each(&:purge)
# rails >= 6.1
ActiveStorage::Blob.missing(:attachments).find_each(&:purge)
这将删除数据库中的记录并删除磁盘上的物理文件,但保留文件所在的文件夹。
ActiveStorage::Blob.unattached.each(&:purge)