ruby-on-rails - active - rails gem upload file
escribir secuencia en clip (5)
Quiero almacenar el archivo adjunto recibido con el uso de clip. Del correo electrónico obtengo part.body y no tengo idea de cómo ponerlo en el modelo de clip de papel. Por ahora, creo el archivo temporal y escribo port.body en él, almaceno este archivo en paperclip y elimino el archivo. Así es como lo hago con el archivo temporal:
l_file = File.open(l_path, "w+b", 0644)
l_file.write(part.body)
oAsset = Asset.new(
:email_id => email.id,
:asset => l_file,
:header => h,
:original_file_name => o,
:hash => h)
oAsset.save
l_file.close
File.delete(l_path)
: asset es mi campo ''has_attached_file''. ¿Hay alguna manera de omitir la creación de archivos y hacer algo como: asset => part.body en Asset.new?
Así es como lo haría, suponiendo que uses la gema del correo para leer el correo electrónico. necesitarás todo el correo electrónico ''parte'', no solo part.body
file = StringIO.new(part.body) #mimic a real upload file
file.class.class_eval { attr_accessor :original_filename, :content_type } #add attr''s that paperclip needs
file.original_filename = part.filename #assign filename in way that paperclip likes
file.content_type = part.mime_type # you could set this manually aswell if needed e.g ''application/pdf''
ahora solo use el objeto de archivo para guardar en la asociación Paperclip.
a = Asset.new
a.asset = file
a.save!
Espero que esto ayude.
Desde ruby 1.9, puedes usar StringIO y define_singleton_method:
def attachment_from_string(string, original_filename, content_type)
StringIO.new(string).tap do |file|
file.define_singleton_method(:original_filename) { original_filename }
file.define_singleton_method(:content_type) { content_type }
end
end
La respuesta de Barlow es buena, pero efectivamente está aplicando parches a la clase StringIO. En mi caso, estaba trabajando con Mechanize :: Download # body_io y no quería contaminar la clase, lo que ocasionó que aparecieran errores inesperados en la aplicación. Así que defino los métodos en la metaclass de instancias así:
original_filename = "whatever.pdf" # Set local variables for the closure below
content_type = "application/pdf"
file = StringIO.new(part.body)
metaclass = class << file; self; end
metaclass.class_eval do
define_method(:original_filename) { original_filename }
define_method(:content_type) { content_type }
end
Me gusta mucho la respuesta de gtd, pero puede ser más simple.
file = StringIO.new(part.body)
class << file
define_method(:original_filename) { "whatever.pdf" }
define_method(:content_type) { "application/pdf" }
end
Realmente no hay necesidad de extraer la "metaclase" en una variable local, solo agregue alguna clase al objeto.
Utilicé una técnica similar para desplegar imágenes en clips
esto debería funcionar, pero no se ha probado:
io = part.body
def io.original_filename; part.original_file_name || ''unknown-file-name''; end
asset = Asset.new(:email=>email)
asset.asset = io
Cuando asignamos el IO directamente a la instancia de paperclip, necesita tener un .original_file_name, así que eso es lo que estamos haciendo en la segunda línea.