在我详细介绍之前,我要直截了当:有没有人想出一种方法让 Carrierwave 将文件保存为时间戳或每个文件唯一的任意字符串?
默认情况下,Carrierwave 将每个文件及其替代版本保存在其自己的目录中(以型号 ID 号命名)。我不喜欢这个,因为不是一个有 1,000 个的目录,而是为了使用大整数,文件(在我的例子中是图片)在其中我们得到一个有 1,000 个子目录的目录,每个子目录有一个或两个文件。呸。
现在,当您将 Uploader 的store_dir
方法覆盖为如下所示时:
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}"
end
你最终得到了我想要的确切行为。所有文件(图片)都进入一个快乐的大文件夹。当对象被删除时,没有更多的子文件夹存在。
只有一个问题。文件冲突。如果你上传了两次delicious_cake.jpg,第二个将覆盖第一个,即使它们是两张不同的美味蛋糕图片!这就是为什么该store_dir
方法在/#{model.id}
它返回的值的末尾加上了额外的原因。
那么该怎么办?在阅读了一下之后,我发现在生成的上传文件中有一个明显的解决方案被注释掉了。
# Override the filename of the uploaded files:
# Avoid using model.id or version_name here, see uploader/store.rb for details.
# def filename
# "something.jpg" if original_filename
# end
经过一番搜索,我发现有人做了以下事情
def filename
@name ||= "#{secure_token}.#{file.extension}" if original_filename
end
这让我想,为什么不这样做
def filename
@name ||= "#{(Time.now.to_i.to_s + Time.now.usec.to_s).ljust(16, '0')}#{File.extname(original_filename)}"
end
就在那时,事情变得非常糟糕。这样做的问题是,filename
显然每个版本的文件都会被调用,所以我们最终会得到像 1312335603175322.jpg 和 thumb_1312335603195323.jpg 这样的文件名。注意到细微的差别了吗?每个文件名都基于filename
该特定版本的调用时间。那根本行不通。
我接下来厌倦了使用model.created_at
时间戳的基础。只有一个问题,第一个版本返回 nil,因为它还没有被放入数据库。
经过进一步思考,我决定在我的图片控制器中尝试以下操作。
def create
if params[:picture] and params[:picture][:image]
params[:picture][:image].original_filename = "#{(Time.now.to_i.to_s + Time.now.usec.to_s).ljust(16, '0')}#{File.extname(params[:picture][:image].original_filename)}"
end
...
这会在 Carrierwave 到达之前覆盖 original_filename 属性,使其成为时间戳。它正是我想要的。文件的原始版本以 1312332906940106.jpg 之类的名称结束,而缩略图版本(或任何其他版本)以 thumb_1312332906940106.jpg 之类的名称结束。
但是,这似乎是一个可怕的黑客攻击。这应该是模型的一部分,或者更好的是安装在模型上的上传器的一部分。
所以,我的问题是,有没有更好的方法来实现这一目标?我是否错过了一些重要的 Carrierwave 使这变得容易?有没有一种不那么明显但更清洁的方式来解决这个问题?工作代码很好,但不难闻的工作代码更好。