Gem 你需要将 CarrierWave 的删除旧文件功能禁用掉!

huacnlee · 2014年10月14日 · 最后由 huacnlee 回复于 2014年10月14日 · 3928 次阅读

CarrierWave 在我接触过的很多个项目中使用,我时常会发现奇怪的问题,用 CarrierWave 实现的头像、封面图等会出现丢图的情况。

这类情况有下面这些:

  1. 列表有 cache,由于用户修改了头像,产生了新的图片 URL,老文件被删除,而对应的地方 cache 没过期;
  2. 产品封面图修改了,但有些地方有手工引用了老的图片 URL(比如查入到了文章正文里面);
  3. 图真的就丢了,和 cache 无关,分析发现新的 URL 以及产生了,但老图、新图都没有。

首先,这里不讨论 Cache 过期的策略

由于这些问题是偶尔发生,并且概率都非常小,所以之前我都一直忽略了,但是随着越来越多的系统里面出现类似的情况,最近我开始分析可能存在的原因。

CarrierWave 在 Model 的 callback 上面挂了:after_save :"remove_previously_stored_#{column}"

这会带来的问题:

  1. 数据库提交失败 rollback 的时候,老图以及被删除了,而新图的文件名没有更新到数据库,导致丢图;
  2. 上面说的老图删除以后引出的一系列微小的问题;

所以,反过来想一下,真的需要删除老图片么?!是的,没必要,不缺那么点儿空间。

解决方法

CarrierWave.configure do |config|
  # 不要在上传新文件的时候,删除老文件
  config.remove_previously_stored_files_after_update = false
end

参考 Ruby China 这个 Commit:

https://github.com/ruby-china/ruby-china/commit/ab932aa9beccd2ef4ce27c5e8d00c0b5c5457f81


我的建议已经合并到了 Carrierwave 里面 https://github.com/carrierwaveuploader/carrierwave/pull/1503/files

一般这种情况下,比如用户头像,不应该用唯一的文件地址么?我这边都是类似用户 ID.jpg,这样的好处是用户即使更新了头像,头像地址仍然不变,这样就不会出现遇到的问题了吧。当然,旧文件肯定就被替换掉了

#1 楼 @chunlea 唯一地址那个是另外一个事情,其实有许多细节的

实际上,Ruby China 现在头像也是这么做的。

那是不是删除记录的时候也不要删除图片?我还没去读代码,仅仅只是猜想,我不确定remove_previously_stored_files_after_update这个会不会对 destroy 产生作用。

#2 楼 @huacnlee 我觉得这个问题挺奇怪的,有机会在研究研究看看

干的漂亮!

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