Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I delete a file in Sinatra after it has been sent via send_file?

Tags:

ruby

sinatra

I have a simple sinatra application that needs to generate a file (via an external process), send that file to the browser, and finally, delete the file from the filesystem. Something along these lines:

class MyApp < Sinatra::Base
  get '/generate-file' do

    # calls out to an external process, 
    # and returns the path to the generated file
    file_path = generate_the_file()  

    # send the file to the browser
    send_file(file_path)

    # remove the generated file, so we don't
    # completely fill up the filesystem.
    File.delete(file_path)

    # File.delete is never called.

  end
end

It seems, however, that the send_file call completes the request, and any code after it does not get run.

Is there some way to ensure that the generated file is cleaned up after it has been successfully sent to the browser? Or will I need to resort to a cron job running a cleanup script on some interval?

like image 549
John Reilly Avatar asked May 10 '10 20:05

John Reilly


3 Answers

send_file is streaming the file, it is not a synchronous call, so you may not be able to catch the end of it to the cleanup the file. I suggest using it for static files or really big files. For the big files, you'll need a cron job or some other solution to cleanup later. You can't do it in the same method because send_file will not terminate while the execution is still in the get method. If you don't really care about the streaming part, you may use the synchronous option.

begin
   file_path = generate_the_file()  
   result File.read(file_path)
   #...
   result # This is the return
ensure
   File.delete(file_path) # This will be called..
end

Of course, if you're not doing anything fancy with the file, you may stick with Jochem's answer which eliminate begin-ensure-end altogether.

like image 56
Akaedintov Avatar answered Oct 17 '22 02:10

Akaedintov


It could be a solution to temporarily store the contents of the file in a variable, like:

contents = file.read

After this, delete the file:

File.delete(file_path)

Finally, return the contents:

contents

This has the same effect as your send_file().

like image 36
Jochem Schulenklopper Avatar answered Oct 17 '22 04:10

Jochem Schulenklopper


Unfortunately there is no any callbacks when you use send_file. Common solution here is to use cron tasks to clean temp files

like image 3
fl00r Avatar answered Oct 17 '22 04:10

fl00r