2013-08-14 9 views
23

Sto usando seguente codice per l'invio del file in Rails.in Ruby on Rails, dopo che il metodo send_file eliminare il file dal server di

 
if File.exist?(file_path) 
    send_file(file_path, type: 'text/excel') 
    File.delete(file_path) 
end 

In questo sto cercando di inviare il file ed eliminare il file dal server una volta che è stato inviato correttamente. Ma sto affrontando il problema è, l'operazione di cancellazione viene eseguita mentre l'invio è in esecuzione e a causa di ciò non vedo nulla nel browser.

Quindi esiste un modo in Rails, una volta completata l'operazione send_file, eliminare il file dal server.

Qualsiasi aiuto su questo sarebbe molto apprezzato.

Grazie,
Chetan

+0

Non questo è possibile all'interno del gestore di richieste, e si vuole un posto di lavoro in ritardo o meccanismo simile a ripulire, permettendo abbastanza tempo per il download di completamento –

risposta

32

Perché stai usando send_file, Rails passerà la richiesta al server HTTP (Nginx, Apache, ecc - See the Rails documentation on send_file regarding X-Sendfile headers). Per questo motivo, quando si tenta di eliminare il file, Rails non sa che è ancora in uso.

Puoi provare a utilizzare send_data invece, che bloccherà fino a quando i dati non verranno inviati, consentendo così alla tua richiesta File.delete di riuscire. Tenete a mente che send_data richiede un flusso di dati come argomento, però, non è un percorso, quindi è necessario aprire il file prima:

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

L'altra opzione sarebbe un processo in background che controlla periodicamente per i file temporanei da eliminare .

+0

Anche tenere a mente che probabilmente si Send_Data utilizzare più risorse per inviare lo stesso contenuto di 'send_file', ma non è necessario ossessionare la differenza, a meno che questa non sia una funzionalità molto utilizzata del sito. –

+0

@NeilSlater Sì, per un file di testo di base che genera rapidamente non dovrebbe essere un grosso problema. Ma per generare file di grandi dimensioni/lenti, una soluzione di lavoro di background + file send_file sarebbe probabilmente migliore. –

+0

Grazie Dylan per aver risposto a questo. In seguito ha lavorato per me: se File.exist (percorso_file) File.open (file_path, 'rb') do | F |? f.read Send_Data, tipo: "application/excel", il nome del file: "file_name.xls" fine fine –

2

Se si sta generando il file che si sta tentando di inviare volare, una soluzione è quella di utilizzare la classe Tempfile:

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 

Contrariamente a quanto indicato nel this question, questo funziona come previsto (il file rimane sul server abbastanza a lungo per essere servito, ma alla fine viene eliminato); this post sembra indicare che questo è dovuto agli aggiornamenti in Rails 3.2.11, qualcosa che non ho potuto verificare.

+0

Sono abbastanza sicuro che se si desidera eliminare in realtà il tempfile, è è necessario fare qualcosa come temp_file.unlink –

+0

@MichaelWu Secondo la [documentazione] (http://www.ruby-doc.org/stdlib-2.1.2/libdoc/tempfile/rdoc/Tempfile.html # method-i-close), TempFile # close con nessun parametro finisce per chiamare #unlink automaticamente, "quando l'oggetto è finalizzato". Ha funzionato come previsto per me. – louije

+4

Non conterei su questo lavorando il 100% delle volte. Cancellerà il file quando il Tempfile è spazzato via e non ci sono garanzie che ciò accada prima che nginx/apache abbia aperto il file. Dipende dall'implementazione interna di send_file in Rails. send_data è un'alternativa migliore. – mrbrdo

1

Questo funziona per me! Con send_data è possibile eliminare il file prima di inviare.

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) 
Problemi correlati