Gem CarrierWave 文件名重复的问题

putty · 2013年11月05日 · 最后由 putty 回复于 2013年11月05日 · 3764 次阅读

xxxUploader 类中的函数实现

def filename
   if original_filename
       @name ||= Digest::MD5.hexdigest(File.dirname(current_path))
         "#{@name}.#{file.extension}"
     end
end
XXXX model类中的定义
mount_uploader :xxx_file, xxxUploader

xxxx controller类中的定义
    Dir.foreach("/home/xxxx/test/") { |file|
      ext_name = File.extname(file)
      if ext_name == ".rar" or ext_name == ".zip" or ext_name == ".7z" then
          xxx_img = XXXX.new
          xxx_img.xxx_file = File.open("/home/xxx/test/" + file )
          xxx_img.save!
      end 
    }   

最后发现model中的xxx_file有重复的名字?

1445 中有 9 个重复的

@huacnlee 大大 确认

你排好版我就帮你看看 😄

@huacnlee 大大,这样的排版可以莫?

都跑了几个月了,昨天查一个 BUG,发现原来是这个引起的

你是说 http://huacnlee.com/blog/carrierwave-upload-store-file-name-config/ 这篇文章

current_path 是 Carrierwave 创建的时候根据时间来的一个地址,理论上是不会重复的呀,我来查查

我是批量导入目录下的文件,一次有 1000 多个,是不是时间太短导入的?我手动导入没有发现这个问题

@huacnlee 就是按照你的这边文章做的

#7 楼 @putty

Carrierwave 的 current_path 的产生方式这这么来的:

Time.now.utc.to_i.to_s + '-' + Process.pid.to_s + '-' + ("%04d" % rand(9999))

https://github.com/carrierwaveuploader/carrierwave/blob/0d6864a84dbed16ef0ed149f332fa3b9f9bd35eb/lib/carrierwave/uploader/cache.rb#L18

我刚刚才 IRB 里面测试了一下

irb(main):017:0> a = []
=> []
irb(main):018:0> 10000.times { a << Time.now.strftime('%Y%m%d-%H%M') + '-' + Process.pid.to_s + '-' + ("%04d" % rand(9999)) }
=> 10000
irb(main):019:0> puts a.count
10000
=> nil
irb(main):020:0> puts a.uniq.count
6228
=> nil

所以,在一瞬间爆发上传请求的时候,重复的概率是有的,确实目前的方法是有问题的,当初我忽略了这个问题,抱歉啊!

如果不用 File.dirname(current_path) 而是直接用 current_path 重复的概率应该没了

还好,只有 9 个,我手动恢复下

def current_path
  file.path if file.respond_to?(:path)
end 

啥原理

@huacnlee 大大,打算提交到https://github.com/ruby-china/ruby-chinamerge上吗?我直接 ruby-china 就好啦?

#12 楼 @putty Ruby China 的我稍后会修改一下,但新的方案我得在看看

谢谢@huacnlee,到时候我直接 fetch+merge 下就好啦

#14 楼 @putty 只是以 Ruby China 目前的场景来看,这种碰撞的概率几乎为 0

@huacnlee 意思说你不会去修改 ruby-china 是吗?

#16 楼 @putty 稍微改了一下,就是目前不该也没问题的

嗯,看到 ruby-china 修改了,不知道为啥加个 Time.now.year?

@huacnlee 不加 Time.now.year 理论上也可以

#19 楼 @putty 我家那个是防止新的 MD5 算法和老的重复,这样就是到了一个新的目录里面去了

@huacnlee 大大 后来我仔细看了下代码发现日志不符合代码预期

def self.generate_cache_id
  Time.now.utc.to_i.to_s + '-' + Process.pid.to_s + '-' + ("%04d" % rand(9999))
end 
def filename 
  if original_filename 
    @name ||= Digest::MD5.hexdigest(current_path)
    Rails.logger.info(">>>>>>>>>>>>>>>>>> #{current_path}    #{File.dirname(current_path)}   #{original_filename} #{cache_id} #{CarrierWave.generate_cache_id}")
    "#{@name}.#{file.extension}"
  end 
end 

打印出来的日志是

xxxxxxx/20131105-1631-9879-1501/__1.zip xxxxxxx/20131105-1631-9879-1501 __1.zip 20131105-1631-9879-1501 20131105-1631-9879-2339

@huacnlee 我错了,我的 Gemfile 'carrierwave', '0.6.2'

谢谢 @huacnlee。结束~(≧▽≦)/~啦啦啦

需要 登录 后方可回复, 如果你还没有账号请 注册新账号