2010-12-14 50 views
30

J'utilise Carrierwave pour télécharger des fichiers, et cela fonctionne.Renommer des fichiers téléchargés avec Carrierwave

Mon problème est de tenter de changer le nom du fichier téléchargé.

Dans le produit uploader.rb il y a une méthode que je pense que je devrais utiliser

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 

Je ne peux pas sembler accéder à des éléments comme « extension » ou « content_type » dans sanitized_file.rb, cette est un peu au-delà de mon niveau de compétence actuel en ce moment.

Des suggestions ou des exercices pour ce faire, c'est-à-dire générer un nom de fichier pour un fichier téléchargé qui fonctionne aussi bien que la valeur par défaut de carrierwave (ne fait rien, mais continue à chaque version)? On dirait que ça devrait être assez simple mais j'ai trébuché dessus.

+2

Je ne comprends pas vraiment votre code avec des commentaires/code tout confondu. Pouvez-vous l'éditer? – lulalala

Répondre

34

Eh bien, un autre problème avec votre générateur de nom de fichier aléatoire est qu'il est possible d'avoir des collisions n'est-ce pas? Vous pourriez éventuellement générer un nom de fichier qui a déjà été généré. Une façon de procéder à ce sujet serait de générer un hachage basé sur les propriétés uniques de l'image, comme le chemin du fichier. Un exemple, de la carrierwave group:

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

Cela va créer un hachage MD5 basé sur le chemin en cours, puis ajoutez l'extension du fichier original à lui.

Editer: Le wiki carrierwave a ajouté un entry avec quelques méthodes sur la façon de créer des noms de fichiers aléatoires et uniques pour tous les fichiers versionnés.

+1

C'est certainement la meilleure réponse. Les hachages sont la bonne solution à ce problème. –

+2

En supposant que l'on a une tâche de rake qui va dans et supprime les fichiers temporaires, la probabilité d'une collision n'est-elle pas simplement d'utiliser File.dirname (current_path)? Je pense qu'une meilleure solution pourrait être d'utiliser created_at en combinaison avec le chemin. – saneshark

+0

Qu'en est-il de l'utilisation d'un uuid? @name = SecureRandom.uuid – Brady

1

L'autre solution semble bon, mais comment je l'ai fait alors était d'avoir un crochet qui a créé une chaîne aléatoire pour un nouveau nom sur la création de l'instance, puis:

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

dans le Uploader. Cela a fonctionné, en mettant la génération de nom aléatoire dans le modèle, puis en l'utilisant.

Je suis curieux de ce qui est plus rapide, plus efficace, raisonnable, son, etc.

+3

Vous devriez marquer ceci comme correct alors. –

1

De l'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

juste faire le préfixe record.id le nom de fichier que vous pouvez faire ce qui suit :

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

Pour avoir un vrai nom de fichier unique (pas presque unique), je recommande d'utiliser la gemme uuid.

à Gemfile ajouter:

gem 'uuid' 

dans 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

devrais-je l'ajouter dans l'uploader? –

+0

oui à l'uploader – ramigg

0

Voici la solution, comment changer le nom du fichier, si store_dir contient déjà le fichier avec le nom exact:

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 

Remarque: Rails.root.join("documents/") est défini comme mon store_dir.

Espérons que cela aide quelqu'un.