2013-08-14 2 views
23

Ich verwende folgenden Code zum Senden der Datei in Rails.In Ruby on Rails, Nach send_file Methode löschen Sie die Datei vom Server

In diesem versuche ich die Datei zu senden und die Datei vom Server zu löschen, sobald es erfolgreich gesendet wurde. Aber ich habe das Problem, dass die Löschoperation ausgeführt wird, während das Senden ausgeführt wird, und deshalb sehe ich nichts im Browser.

So gibt es eine Möglichkeit in Rails, sobald die Operation send_file abgeschlossen ist, löschen Sie die Datei vom Server.

Jede Hilfe zu diesem Thema würde sehr geschätzt werden.

Danke,
Chetan

+0

ich nicht, dies ist möglich in den Request-Handler, und Sie werden einen verzögerten Job oder ein ähnlichen Mechanismus zu bereinigen, so dass genügend Zeit für den Download von im Auge behalten –

Antwort

32

Weil Sie send_file verwenden, Rails die Anforderung entlang zu Ihrem HTTP-Server (- See the Rails documentation on send_file regarding X-Sendfile headers nginx, Apache, etc.) übergeben. Wenn Sie versuchen, die Datei zu löschen, weiß Rails daher nicht, dass es weiterhin verwendet wird.

Sie können stattdessen versuchen, send_data zu verwenden, die blockiert, bis die Daten gesendet werden, so dass Ihre File.delete Anfrage erfolgreich sein kann. Beachten Sie, dass send_data einen Datenstrom als Argument erfordert aber keinen Weg, so müssen Sie die Datei öffnen, zuerst:

File.open(file_path, 'r') do |f| 
    send_data f.read, type: "text/excel" 
end 
File.delete(file_path) 

Die andere Option wäre ein Hintergrund-Job sein, der in regelmäßigen Abständen überprüft, um temporäre Dateien zu löschen .

+0

Auch abgeschlossen mögen, dass send_data wird wahrscheinlich Verwenden Sie mehr Ressourcen, um den gleichen Inhalt wie 'send_file' zu ​​senden, aber müssen Sie sich nicht über den Unterschied Gedanken machen, es sei denn, dies wird ein stark genutztes Feature der Site sein. –

+0

@NeilSlater Ja, für eine einfache Textdatei, die schnell generiert wird, sollte es keine große Sache sein. Aber zum Erzeugen großer/langsamer Dateien wäre eine send_file + Hintergrund-Job-Lösung wahrscheinlich besser. –

+0

Danke Dylan für die Antwort auf diese Frage. Folgendes funktioniert für mich: wenn File.exist? (File_path) File.open (file_path, 'rb') do | f | send_data f.read, Typ: "application/excel", Dateiname: "file_name.xls" Ende Ende –

2

Wenn Sie auf die fliegen, um die Datei generieren, die Sie senden möchten, ist eine Lösung, die Tempfile Klasse zu verwenden:

begin 
    # The second argument is optional: 
    temp_file = Tempfile.new(filename, temp_directory) 

    # ... edit temp_file as needed. 

    # By default, temp files are 0600, 
    # so this line might be needed depending on your configuration: 
    temp_file.chmod(0644) 
    send_file temp_file 
ensure 
    temp_file.close 
end 

Im Gegensatz zu dem, was in this question angegeben, dies funktioniert wie erwartet (die Datei bleibt lange genug auf dem Server, um bedient zu werden, wird aber letztendlich gelöscht); this post scheint darauf hinzuweisen, dass dies auf Updates in Rails 3.2.11 zurückzuführen ist, etwas, das ich nicht überprüfen konnte.

+0

Ich bin ziemlich sicher, wenn Sie wollen, um tatsächlich die tempfile zu löschen, Sie muss etwas tun wie temp_file.unlink –

+0

@MichaelWu Laut der [Dokumentation] (http://www.ruby-doc.org/stdlib-2.1.2/libdoc/tempfile/rdoc/Tempdatei.html # method-i-close), TempFile # Schließen ohne Parameter endet mit dem automatischen Aufruf von #unlink, "wenn das Objekt finalisiert ist". Es hat wie erwartet für mich funktioniert. – louije

+4

Ich würde nicht 100% der Zeit damit rechnen. Es wird die Datei löschen, wenn die Temp-Datei Garbage Collected ist, und es gibt keine Garantien, dass dies geschehen wird, bevor Nginx/Apache die Datei geöffnet hat. Dies hängt von der internen Implementierung von send_file in Rails ab. send_data ist eine bessere Alternative. – mrbrdo

1

Das funktioniert für mich! Mit send_data können Sie Datei vor dem Senden löschen.

file = File.open(Rails.root.join('public', 'uploads', filename), "rb") 
contents = file.read 
file.close 

File.delete(filepath) if File.exist?(filepath) 

send_data(contents, :filename => filename) 
Verwandte Themen