使用Carrierwave重命名上传的文件

时间:2010-12-14 19:48:39

标签: ruby-on-rails ruby file-upload carrierwave

我正在使用Carrierwave上传文件,我让它正常工作。

我的问题是尝试更改上传文件的名称。

在生成的uploader.rb中有一个我认为我应该使用的方法

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

我似乎无法在sanitized_file.rb中访问“extension”或“content_type”等项目,所以现在这有点超出了我目前的技能水平。

执行此操作的任何建议或练习,即为上传的文件生成文件名,该文件与carrierwave默认值一样(不执行任何操作,但会继续执行每个版本)?似乎它应该足够简单,但我偶然发现了这一点。

6 个答案:

答案 0 :(得分:34)

那么,你的随机文件名生成器的另一个问题是它可能会发生冲突吗?您可能会生成已生成的文件名。 一种方法是以某种方式基于图像的唯一属性(如文件路径)生成哈希。例如,来自carrierwave group

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

这将根据当前路径创建MD5哈希,然后将原始文件的扩展名附加到其上。

编辑:carrierwave wiki添加了一个entry,其中包含一些有关如何为所有版本化文件创建随机和唯一文件名的方法。

答案 1 :(得分:5)

要拥有真正独特的文件名(几乎不是唯一的)我建议使用uuid gem。

在Gemfile中添加:

gem 'uuid'

在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

答案 2 :(得分:1)

另一个解决方案看起来很不错,但我是如何做的就是在实例创建时为一个新名称创建一个随机字符串,然后:

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

在上传器中。

这很有效,将随机名称生成作为模型的一部分,然后让carrierwave使用它。

我很好奇哪个更快,更有效,更合理,更健全等。

答案 3 :(得分:1)

来自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

答案 4 :(得分:1)

要将record.id前缀作为文件名,您可以执行以下操作:

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

答案 5 :(得分:0)

以下是解决方案,如果store_dir已包含确切名称的文件,如何更改文件名称:

  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

注意Rails.root.join("documents/")定义为我的store_dir

希望它有所帮助。