According to Rails (edge6.0
) guides, we can do maintenance work for ActiveStorage used in System Test and Integration Test by calling the following statement respectively
# System Test
FileUtils.rm_rf("#{Rails.root}/storage_test")
# Integration Test
FileUtils.rm_rf(Rails.root.join('tmp', 'storage'))
I want to know -
Are there any Rails built-in functions or rake commands or gems to do the following?
ActiveStorage::Blob
records those are no longer associated with any ActiveStorage::Attachment
record)ActiveStorage::Blob
record)I do not see any relevant rake tasks with rails --tasks
.
Currently, I am using
# 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
and this script to clean orphan files (via 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)}"
Well there is a easier way now, not sure when it changed, but there is one caveat (it leaves the empty folder):
# 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)
This will delete the record in the database and delete the physical file on disk, but leave the folders the file existed in.