2011-02-04 17 views
6

Actualmente estoy intentando adjuntar archivos de imagen a un modelo directamente desde un archivo zip (es decir, sin guardarlos primero en un disco). Parece que debería haber una forma más clara de convertir un ZipEntry en un Tempfile o archivo que pueda almacenarse en la memoria para pasarlo a otro método u objeto que sepa qué hacer con él.¿Cómo obtengo un objeto de archivo temporal (del tipo de contenido correcto, sin escribir en el disco) directamente desde un ZipEntry (RubyZip, Paperclip, Rails 3)?

Aquí está mi código:

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 

Pero el problema es que photo.image es un archivo adjunto (a través de un clip) para el modelo, y la asignación de algo como un archivo adjunto requiere que algo sea un objeto File. Sin embargo, no puedo entender cómo convertir un ZipEntry en un archivo. La única forma que he visto de abrir o crear un archivo es usar una cadena en su ruta, lo que significa que tengo que extraer el archivo a una ubicación. Realmente, eso parece tonto. ¿Por qué no puedo simplemente extraer el archivo ZipEntry a la secuencia de salida y convertirlo a un archivo allí?

Así que la última pregunta: ¿Puedo extraer un ZipEntry de un archivo Zip y convertirlo directamente en un objeto File (o adjuntarlo directamente como un objeto Paperclip)? ¿O estoy atrapado en realidad almacenándolo en el disco duro antes de que pueda adjuntarlo, aunque esa versión se eliminará al final?

ACTUALIZACIÓN Gracias a los campos de arándanos, creo que estoy un poco más cerca de mi solución. Aquí está la línea de código que he añadido, y me da la archivo temporal/archivo que necesito:

photo.image = zip_file.get_output_stream image 

Sin embargo, mi Photo objeto no aceptará el archivo que está siendo aprobada, ya que no es un image/jpeg. De hecho, al marcar content_type del archivo, se muestra application/x-empty. Creo que esto puede deberse a que la obtención del flujo de salida parece agregar una marca de tiempo al final del archivo, por lo que termina luciendo como imagename.jpg20110203-20203-hukq0n. Editar: Además, el archivo temporal que crea no contiene ningún dato y es de tamaño 0. Así que parece que esta podría no ser la respuesta.

Entonces, la siguiente pregunta: ¿Alguien sabe cómo conseguir esto para darme un archivo de imagen/jpeg?

ACTUALIZACIÓN:

He estado jugando con esto un poco más. Parece que el flujo de salida no es el camino a seguir, sino más bien un flujo de entrada (que es lo que siempre me ha confundido). Usando get_input_stream en ZipEntry, obtengo los datos binarios en el archivo. Creo que ahora solo tengo que averiguar cómo conseguir esto en un archivo adjunto de Paperclip (como un objeto File). Intenté presionar ZipInputStream directamente en el archivo adjunto, pero, por supuesto, eso no funciona. Realmente me cuesta creer que nadie haya intentado convertir un ZipEntry extraído como un archivo. ¿Hay alguna razón para que esto se considere una mala práctica de programación? Me parece que omitir el disco de escritura para un archivo temporal sería perfectamente aceptable y compatible con algo así como la gestión de archivos Zip.

De todos modos, la pregunta sigue en pie:

¿Hay una manera de convertir un flujo de entrada a un objeto de archivo (o archivo temporal)? Preferiblemente sin tener que escribir en un disco.

Respuesta

1

Consulte los mensajes get_input_stream y get_output_stream en ZipFile.

+0

He intentado esto a cabo. El uso de zip_file.get_output_stream (image) resultó en un archivo. Sin embargo, el modelo parece interpretar ese archivo como 'application/x-empty', lo que hace que falle. También parece estar leyendo el nombre del archivo como 'nombre_imagen.jpg20110203-20203-1lyjn3i', que supongo que es la marca de tiempo estándar que el clip proporciona a sus imágenes para el seguimiento de la versión. ¿Conoces una forma de asegurarte de que se lea como un jpeg? –

+1

En realidad, acabo de comprobarlo. La secuencia de salida se abre como un Tempfile. Esa marca de tiempo se agrega cuando se crea ese archivo Tempfile. Acabo de verificar content_type del Tempfile que se extrae, y sale como application/x-empty. –

6

probar este

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

Esto funciona, pero la sintaxis para la creación del archivo de temp era incorrecta. Lo he editado para usar una sintaxis diferente. – siamii

+0

En este ejemplo, está configurando user.avatar en un hash. ¿Es User.avatar un Paperclip :: Attachment? Si es así, ¿cómo puedes pasar un hash? Lo probé, y no funciona para mí. Paperclip: Attachment tiene un conjunto de "adaptadores io" para diferentes tipos de objetos (como StringIO y Tempfile), pero miré a través de los io_adapters, y no puedo ver uno que maneje un hash. –

Cuestiones relacionadas