2010-12-14 12 views
30

Estoy usando Carrierwave para subir archivos, y lo tengo funcionando.Renombrar archivos cargados con Carrierwave

Mi problema es intentar cambiar el nombre del archivo cargado.

En la generada uploader.rb hay un método que creo que debería usar

def filename 
    "something.jpg" if original_filename 
    basename = "what"+orginal_filename if original_filename, works 
    basename = (0...8).map{65.+(rand(25)).chr}.join if original_filename # will create a random name for each version, e.g. the orginal, the thumb, and the filename in the db, useless 
end 

Me parece que no puede acceder a los elementos como la 'extensión' o 'content_type' en sanitized_file.rb, por lo que este está un poco más allá de mi nivel de habilidad actual en este momento.

Cualquier sugerencia o ejercicios para hacer esto, es decir, generar nombre de archivo para un archivo cargado que funciona tan bien como el predeterminado de carrierwave (no hacer nada, pero continúa en cada versión)? Parece que debería ser lo suficientemente simple, pero me he tropezado con esto.

+2

No entiendo muy bien su código con comentarios/código todo mezclado. ¿Puedes editarlo? – lulalala

Respuesta

34

Bueno, otro problema con su generador de nombres aleatorios es que es posible tener colisiones ¿no? Posiblemente pueda generar un nombre de archivo que ya se haya generado. Una forma de hacerlo sería generar de alguna manera un hash basado en propiedades únicas de la imagen, como la ruta del archivo. Un ejemplo, de la carrierwave group:

def filename 
    if original_filename 
    @name ||= Digest::MD5.hexdigest(File.dirname(current_path)) 
    "#{@name}.#{file.extension}" 
    end 
end 

Esto creará un hash MD5 basado en la trayectoria de la corriente y luego añadir la extensión del archivo original a la misma.

Editar: La wiki de carrierwave agregó un entry con algunos métodos sobre cómo crear nombres de archivo aleatorios y únicos para todos los archivos versionados.

+1

Esta es definitivamente la mejor respuesta. Los hashes son la solución correcta para este problema. –

+2

Suponiendo que uno tiene una tarea de rake que entra y elimina archivos temporales, ¿no es bastante alta la probabilidad de una colisión usando File.dirname (current_path)? Creo que una mejor solución podría ser usar created_at en combinación con la ruta. – saneshark

+0

¿Qué tal usar un uuid? @name = SecureRandom.uuid – Brady

1

La otra solución se ve bien, pero cómo lo hice entonces era tener un gancho que creó una cadena aleatoria para un nuevo nombre en la creación de instancias, entonces:

def filename 
    "#{model.randomstring}.#{model.image.file.extension}" 
end 

en el cargador.

Eso funcionó, poniendo la generación de nombres aleatorios como parte del modelo, y luego usando carrierwave.

Tengo curiosidad por lo que es más rápido, más eficaz y razonable, sonido, etc.

+3

Debería marcar esto como correcto entonces. –

1

Desde el Google Group:

def filename 
    @name ||= "#{secure_token}.#{file.extension}" if original_filename 
end 

private 

def secure_token 
    ivar = "@#{mounted_as}_secure_token" 
    token = model.instance_variable_get(ivar) 
    token ||= model.instance_variable_set(ivar, ActiveSupport::SecureRandom.hex(4)) 
end 
1

hacer sólo el prefijo record.id el nombre de archivo que puede hacer lo siguiente :

class MyUploader < CarrierWave::Uploader::Base 

    storage :file 

    def store_dir 
    model.class.to_s.underscore.pluralize 
    end 

    def filename 
    model.id ? "#{model.id}-#{original_filename}" : original_filename 
    end 

    def url 
    "/#{store_dir}/#{model.id}-#{model.file_before_type_cast}" 
    end 
end 
4

Para tener un nombre de archivo único (no casi único) Recomiendo usar la gema uuid.

en Gemfile añadir:

gem 'uuid' 

en file_uploader.RB:

def filename 
    if original_filename 
    if model && model.read_attribute(mounted_as).present? 
     model.read_attribute(mounted_as) 
    else 
     @name ||= "#{mounted_as}-#{uuid}.#{file.extension}" 
    end 
    end 
end 

protected 

def uuid 
    UUID.state_file = false 
    uuid = UUID.new 
    uuid.generate 
end 
+0

¿debería agregar esto en la herramienta de subida? –

+0

sí al que subió – ramigg

0

Aquí está la solución, cómo cambiar el nombre del archivo, si store_dir ya contiene el archivo con el nombre exacto:

if File.exists?(Rails.root.join("documents/" + "#{file.filename}")) && !path.to_s.eql?(Rails.root.join("documents/" + original_filename).to_s) 
    @name ||= File.basename(original_filename, '.*') + Digest::MD5.hexdigest(File.dirname(current_path)).from(25) 
    "#{@name}.#{file.extension}" 
    else 
    "#{original_filename}" 
    end 

Nota: Rails.root.join("documents/") se define como mi store_dir.

Espero que ayude a alguien.

Cuestiones relacionadas