Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Delete folder after send_file in Rails

I'm sending the file file.txt from my Rails controller using send_file, and then delete the folder containing it.

send_file("#{Rails.root}/public/folder/file.txt")
FileUtils.remove_dir "#{Rails.root}/public/folder", true

When I did this, file.txt was sent and deleted. However, folder was not deleted. But if I remove the send_file line, then folder will be deleted.

How do I make it delete folder?

EDIT: Interestingly, I found that inside folder there is a hidden file called .__afs2B0C, probably preventing the deletion. I have no idea how this file is created! The file stays for only around 15 minutes before disappearing.

EDIT2: I've tried inspecting the content of the temp file with vi, but it's unreadable gibberish. When I removed only the send_file line, the folder was correctly deleted. When I removed only the FileUtils.remove_dir line, the folder contains no temp file.

like image 300
JJ Beck Avatar asked Feb 19 '23 12:02

JJ Beck


2 Answers

Are you sure the send_file is not still sending the file when you are removing the dir, it may be asynchronous if it uses X-SendFile? That would cause an error when trying to remove the dir.

So you should probably be queuing this delete action, or doing it with a sweeper later, rather than trying to do it straight after sending the file to streaming.

I'm not completely clear on which file you are sending, so it would be useful to include an actual example of file path, and file type, and how it is created in your question.

Possible help with debugging:

Log in and monitor the folder while you perform the following actions:

  • Write out a very large file (> 60MB say), and check there is no invisible file created during your file creation process - I'm not clear on which file you are actually sending
  • Set up a large file transfer on a slow connection, and watch for the creation and possibly growing of this file (it might be related to compressing the file served on the fly for example).

Given that sendfile may still be sending (for large files) via the web server (x-send-file is now default) when you try to delete, I'd try looking into delayed solutions.

Possible solutions:

  • Use send_data rather than send_file (if files are small)
  • Schedule the deletion of the folder for later with something like delayed_job
  • Set up a sweeper which removes the folders at the end of each day
like image 167
Kenny Grant Avatar answered Feb 27 '23 01:02

Kenny Grant


Not sure why that hidden file is there, it could be an offshoot of X-send-file or even of wget (partial progress or something).

Ideally, you should use Tempfile to do things like this. The code is based of you're comment about what you are doing. Also, I am using two gems one for downloading and another for zipping. This way, you don't need to make a folder at all, just a zip file directly. All the content files of the zip will be deleted on their own. After downloading the zip just delete it. Here also I should mention that you could run into a glitch somewhere, since the send_file will hand over the transfer to the webserver, and as such you don't the rails process to delete the file while it is still being served. So even with this, and it working well on localhost, I would strongly advise using a custom scheduled background garbage collector in production.

require 'open-uri'
require 'zip/zip'
zip_path = "#{Rails.root}/public/test.zip"
urls_to_fetch = ['abc.com', 'xyz.com']

Zip::ZipFile.open(zip_path, Zip::ZipFile::CREATE) do |zipfile|
    urls_to_fetch.each_with_index do |url, index|
        # intialize new temp file
        file = Tempfile.new(index.to_s)
        # fetch the file using open-uri or wget and save it as a tmpfile
        open(url, 'rb') do |read_file|
            file.write(read_file.read)
        end
    end
    # add the temp file to the list of files to zip
    zipfile.add(File.basename(file), file.path)
end
# send the zipfile for download
send_file zip_path
# delete the zipfile
FileUtils.rm zip_path

However, this should not be mandatory. If you are doing things without Tempfiles, please check the rights that the rails runner has on the target directory.

The FileUtils documentation has details regarding local security vulnerabilities when trying to delete files / folders.

like image 29
vvohra87 Avatar answered Feb 27 '23 01:02

vvohra87