帮酷LOGO
0 0 评论
文章标签:Carrier  Carrierwave  CAR  存储  

在应用程序达到一定数量的上传文件后,我使用carrierWave gem上传文件并遇到一个文件存储问题。

我用一个User模型和avatar字段来上传用户照片。

当数据库中的用户数超过32768时,我开始在日志中收到"Too many links"的错误。


Errno::EMLINK - Too many links - /home/sites/apps/binaryfunction/releases/20140110162610/public/uploads/user/avatar/42435

我运行以下命令检查文件数量


$ cd /home/sites/apps/binaryfunction/releases/20140110162610/public/uploads/user/avatar

$ ls | wc -l

我发现avatar目录里的文件数已经达到了32768

如何修复它

目录下的文件有最大限制。

这取决于你的发行版使用什么文件系统,

每个文件系统都有目录中的文件数量限制,比如,

ext2 :- > 32768

ext3 :- > 31998

ext4 :- > 64000

在达到此数字后,开始报错"Too many links"

生成上传器时,CarrierWave为我们提供了默认存储路径,

通常AvatarUploader看起来像


class AvatarUploader < CarrierWave::Uploader::Base
 def store_dir
 "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
 end
end

所有的文件将存储在uploads/user/avatar/目录中,用于存储用户的头像。

对于user#id 1,它就是uploads/user/avatar/1.png

在你达到最大文件数之前,这将正常工作(例如,对于ext2 32768 )。

这意味着在数量到达32768之后,用户的头像将不会被保存,因为你的文件系统不允许超过dir中的最大数量。

不用担心,我在这里有解决方案:- )


users/avatar/000/000/013/small/1

在这里可以看到,它们有嵌套的目录"000/000/013"

他们把这个叫做id_partition

但是CarrierWave默认情况下没有这个嵌套目录结构。

让我们用CarrierWave上传器实现这个。


class AvatarUploader < CarrierWave::Uploader::Base
 def store_dir
 "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{id_partition}/#{model.id}"
 end

 private

 def id_partition
 case id = model.id
 when Integer
 ("%09d" % id).scan(/d{3}/).join("/")
 # can add more checks if you have other id type (i.e. string for monogdb)
 else
 nil
 end
 end
end

使用上面的id_partition,我们把目录嵌套在


"000/000/001"

如果文件数达到1000,它将创建另一个嵌套目录,例如,


"000/001/000"

所以我们已经解决了AvatarUploader问题,

我建议创建一个BaseUploader并将此方法放入其中,其他可以简单地继承BaseUploader


class BaseUploader < CarrierWave::Uploader::Base
 def store_dir
 "uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{id_partition}/#{model.id}"
 end

 private

 def id_partition
 case id = model.id
 when Integer
 ("%09d" % id).scan(/d{3}/).join("/")
 else
 nil
 end
 end
end

AvatarUploader将成为


class AvatarUploader < BaseUploader
end

要验证这个id_partition工作,你可以简单地编写一个测试程序


require 'spec_helper'

describe BaseUploader do
 describe 'store_dir' do
 it 'should have id_partition included' do
 model_id = 123
 uploader = BaseUploader.new
 model = double(id: model_id)
 uploader.stub(:model).and_return(model)

 expect(uploader.store_dir).to match(/000/000/#{model_id}/#{model_id}/)
 end

 it 'should have another id_partition when id is higher' do
 model_id = 1001
 uploader = BaseUploader.new
 model = double(id: model_id)
 uploader.stub(:model).and_return(model)

 expect(uploader.store_dir).to match(/000/001/001//)
 end
 end
end

这样做可以很容易地解决CarrierWave中的"Too many links"问题,避免在一个文件夹中包含过多的文件。

我知道,当你到达此数量的文件时,要迁移所有上传的文件有点困难,因此最好一开始就这么做,以免将来出现问题。

我希望这篇文章对你有帮助。

这里还有一些其他的文章,你可以找到更多的信息。

Paperclip id_partition

mkdir(): Too Many Links,它是什么以及如何修复



文章标签:CAR  存储  Carrier  Carrierwave  

Copyright © 2011 HelpLib All rights reserved.    知识分享协议 京ICP备05059198号-3  |  如果智培  |  酷兔英语