2011-02-04 10 views
6

Attualmente sto provando ad allegare file immagine a un modello direttamente da un file zip (cioè senza prima salvarli su un disco). Sembra che ci dovrebbe essere un modo più chiaro di convertire uno ZipEntry in un Tempfile o un File che può essere memorizzato in memoria per essere passato ad un altro metodo o oggetto che sa cosa fare con esso.Come ottengo un oggetto File temporaneo (di tipo contenuto corretto, senza scrittura su disco) direttamente da un ZipEntry (RubyZip, Paperclip, Rails 3)?

Ecco il mio codice:

def extract (file = nil) 
    Zip::ZipFile.open(file) { |zip_file| 
    zip_file.each { |image| 
     photo = self.photos.build 
     # photo.image = image # this doesn't work 
     # photo.image = File.open image # also doesn't work 
     # photo.image = File.new image.filename 
     photo.save 
    } 
    } 
end 

Ma il problema è che photo.image è un allegato (via graffetta) per il modello, e l'assegnazione di qualcosa come un allegato che richiede qualcosa di cui essere un oggetto File. Tuttavia, non posso per la vita di me capire come convertire un ZipEntry in un file. L'unico modo che ho visto di aprire o creare un file è di usare una stringa sul suo percorso, ovvero devo estrarre il file in una posizione. Davvero, sembra solo sciocco. Perché non posso semplicemente estrarre il file ZipEntry nel flusso di output e convertirlo in un file lì?

Quindi l'ultima domanda: Posso estrarre un ZipEntry da un file Zip e trasformarlo direttamente in un oggetto File (o collegarlo direttamente come oggetto Paperclip)? O sono bloccato effettivamente memorizzandolo sul disco rigido prima che possa collegarlo, anche se quella versione verrà eliminata alla fine?

UPDATE Grazie ai campi di mirtilli, penso di essere un po 'più vicino alla mia soluzione. Ecco la linea di codice che ho aggiunto, e mi dà il File Temporanei/file che ho bisogno:

photo.image = zip_file.get_output_stream image 

Tuttavia, il mio Photo oggetto non accetterà il file che sta ottenendo passato, dal momento che non è un image/jpeg. In effetti, il controllo dello content_type del file mostra application/x-empty. Penso che questo potrebbe essere dovuto al fatto che ottenere il flusso di output sembra accodare un timestamp alla fine del file, in modo che finisca con l'apparire come imagename.jpg20110203-20203-hukq0n. Modifica: Inoltre, il tempfile creato non contiene dati ed è di dimensione 0. Quindi sembra che questa potrebbe non essere la risposta.

Quindi, la prossima domanda: qualcuno sa come ottenere questo per darmi un file immagine/jpeg?

UPDATE:

Ho giocato in giro con questo un po 'di più. Sembra che il flusso di output non sia la strada da percorrere, ma piuttosto un flusso di input (che mi ha sempre confuso). Usando get_input_stream su ZipEntry, ottengo i dati binari nel file. Penso che ora ho solo bisogno di capire come ottenere questo in un allegato Paperclip (come un oggetto File). Ho provato a inserire ZipInputStream direttamente nell'allegato, ma ovviamente non funziona. Trovo davvero difficile credere che nessuno abbia provato a lanciare ZipEntry estratto come file. C'è qualche ragione per cui questa sarebbe considerata una cattiva pratica di programmazione? Mi sembra che saltare la scrittura del disco per un file temporaneo sarebbe perfettamente accettabile e supportato in qualcosa come la gestione degli archivi Zip.

In ogni caso, la questione si ferma:

Esiste un modo di conversione di un flusso di input a un oggetto file (o File Temporanei)? Preferibilmente senza dover scrivere su un disco.

risposta

1

Controlla i messaggi get_input_stream e get_output_stream su ZipFile.

+0

ho provato questo fuori. L'utilizzo di zip_file.get_output_stream (immagine) ha prodotto un file. Tuttavia, il modello sembra interpretare quel file come 'application/x-empty', che lo fa fallire. Sembra che stia leggendo il nome del file come "image_name.jpg20110203-20203-1lyjn3i", che presumo sia il timestamp standard che paperclip fornisce alle immagini per il tracciamento della versione. Sai di un modo per assicurarti che sia letto come jpeg? –

+1

In realtà, ho appena controllato. Il flusso di output è aperto come Tempfile. Questo timestamp viene aggiunto quando viene creato quel Tempfile. Ho appena controllato content_type del Tempfile estratto e uscito come application/x-empty. –

6

Prova questa

Zip::ZipFile.open(params[:avatar].path) do |zipfile| 
    zipfile.each do |entry| 
    filename = entry.name 
    basename = File.basename(filename) 

    tempfile = Tempfile.new(basename) 
    tempfile.binmode 
    tempfile.write entry.get_input_stream.read 

    user = User.new 
    user.avatar = { 
     :tempfile => tempfile, 
     :filename => filename 
    } 
    user.save 

    end 
end 
+0

Funziona, ma la sintassi per la creazione di tempfile non è corretta. L'ho modificato per usare una sintassi diversa. – siamii

+0

In questo esempio, si imposta user.avatar su un hash. User.avatar è un Paperclip :: Attachment? Se è così, come puoi passare in un hash? L'ho provato e non funziona per me. Paperclip: Attachment ha un set di "io adapters" per diversi tipi di oggetti (come StringIO e Tempfile), ma ho guardato attraverso io_adapters e non posso vederne uno che gestisca un hash. –