xer*_*rph 5 ruby-on-rails carrierwave ruby-on-rails-3.1
使用carrierwave上传器上传图片,尝试使用md5校验和作为文件名提供上传图片的唯一性
看起来我做错了什么
模型定义如下:
class Image < ActiveRecord::Base
attr_accessible :description, :img
mount_uploader :img, ImageUploader
Run Code Online (Sandbox Code Playgroud)
我的上传器代码如下:
class ImageUploader < CarrierWave::Uploader::Base
include CarrierWave::MiniMagick
storage :file
def store_dir
"images/#{filename[0,2]}"
end
def md5
@md5 ||= ::Digest::MD5.file(current_path).hexdigest
end
def filename
@name ||= "#{md5}#{::File.extname(current_path)}" if super
end
Run Code Online (Sandbox Code Playgroud)
首先,我怀疑每次查询图像条目以显示时,这种方法都会计算校验和
其次,保存图像条目后,每隔一个img.original_filename img.filename img.path img.current_path似乎都未定义,并出现以下错误:
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.[]
app/uploaders/image_uploader.rb:17:in `store_dir'
carrierwave (0.5.7) lib/carrierwave/uploader/store.rb:43:in `store_path'
carrierwave (0.5.7) lib/carrierwave/storage/file.rb:41:in `retrieve!'
carrierwave (0.5.7) lib/carrierwave/uploader/store.rb:95:in `block in retrieve_from_store!'
carrierwave (0.5.7) lib/carrierwave/uploader/callbacks.rb:17:in `with_callbacks'
carrierwave (0.5.7) lib/carrierwave/uploader/store.rb:94:in `retrieve_from_store!'
carrierwave (0.5.7) lib/carrierwave/mount.rb:311:in `uploader'
Run Code Online (Sandbox Code Playgroud)
任何形式的帮助或提示表示赞赏
更新:
以这种方式更改上传器:
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.[]
app/uploaders/image_uploader.rb:17:in `store_dir'
carrierwave (0.5.7) lib/carrierwave/uploader/store.rb:43:in `store_path'
carrierwave (0.5.7) lib/carrierwave/storage/file.rb:41:in `retrieve!'
carrierwave (0.5.7) lib/carrierwave/uploader/store.rb:95:in `block in retrieve_from_store!'
carrierwave (0.5.7) lib/carrierwave/uploader/callbacks.rb:17:in `with_callbacks'
carrierwave (0.5.7) lib/carrierwave/uploader/store.rb:94:in `retrieve_from_store!'
carrierwave (0.5.7) lib/carrierwave/mount.rb:311:in `uploader'
Run Code Online (Sandbox Code Playgroud)
current_path似乎是指表单提交的临时文件的完整路径,因此对扩展名提取有效,摘要计算
img_identifier代表持久化结果文件名,因此对前缀提取有效,因为我们store_dir
仍然不确定这种方法是否引起了任何警告
也仍然不相信应该执行文件唯一性验证的方式
更新:
我before_validation在我的模型类中添加了这个回调:
def store_dir
"images/#{model.img_identifier[0,2]}"
end
def filename
@name ||= "#{md5}#{::File.extname(current_path)}"
end
protected
def md5
var = :"@#{mounted_as}_md5"
model.instance_variable_get(var) or model.instance_variable_set(var, ::Digest::MD5.file(current_path).hexdigest)
end
Run Code Online (Sandbox Code Playgroud)
这里checksum是我的模型的数据库表的独立字符串字段
这是因为它复制了相当多余的img一般领域,但我仍然无法找出方法来验证的独特性img本身。
更新:
以这种方式远离数据库冗余。在我的模型中:
validates_uniqueness_of :checksum
before_validation :assign_checksum
def assign_checksum
self.checksum = img.md5 if img.present? and img_changed?
end
Run Code Online (Sandbox Code Playgroud)
现在没有必要在checksum现场
1.当你定义store_dir..文件名时似乎是NIL!
这似乎是立即出现的错误 -尝试使用puts语句打印出文件名设置的内容。
如果文件名是 NIL,您将看到以下错误:
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.[]
app/uploaders/image_uploader.rb:17:in `store_dir'
Run Code Online (Sandbox Code Playgroud)
笔记:
您正在覆盖filename和 store_dir ...并在 store_dir 的定义中使用 filename ...这里可能存在“先有鸡还是先有蛋”类型的问题..最好检查一下
store_dir应该只是一个目录,例如/somewhere/on/your/disk/images
文件名应该只是一个没有路径的文件名,例如24371592d9ea16625854ed68ac4b5846,或 24371592d9ea16625854ed68ac4b5846.jpg
例如检查这两个在代码中如何使用store.rb (在下面的末尾)
问题:
使用filename[0,2]- 您正在使用带有 MD5-sum 2 字母前缀的目录来存储图像?
2. 旁注:什么是current_path?似乎用词不当。应该是路径+文件名,而不仅仅是路径
3. 检查第二个代码片段(如下)store.rb
似乎您设置store_dir为相对目录——这非常脆弱且容易出错..将其设置为绝对路径(以“/”开头)可能是一个更好的主意
4. 尝试将 filename 和 store_dir 设置为常量以进行调试
就像健全性检查一样,当您执行以下操作时它是否有效:
def store_dir
'/tmp/' # from the source code, it looks like this needs to start with '/' !!
end
def filename
'my_uploaded_file'
end
Run Code Online (Sandbox Code Playgroud)
在将文件名设置为 MD5 总和之前应该可以工作。
来自源代码: (0.5.7)
lib/carrierwave/storage/file.rb
lib/carrierwave/uploader/store.rb
您可以覆盖 CarrierWave::Uploader::Store#filename以指向您选择的文件名(请参阅源代码):
在 CarrierWave::Uploader::Base 中覆盖它应该可以工作,因为 'Store' 包含在 'Base' 中;这会覆盖默认文件名。
从store.rb
# Override this in your Uploader to change the filename.
#
# Be careful using record ids as filenames. If the filename is stored in the database
# the record id will be nil when the filename is set. Don't use record ids unless you
# understand this limitation.
#
# Do not use the version_name in the filename, as it will prevent versions from being
# loaded correctly.
#
# === Returns
#
# [String] a filename
#
def filename
@filename
end
Run Code Online (Sandbox Code Playgroud)
您还可以检查缓存的文件名,计算其 MD5-sum (或更好的 SHA1 sum),然后使用结果来命名文件。
从store.rb
# Calculates the path where the file should be stored. If +for_file+ is given, it will be
# used as the filename, otherwise +CarrierWave::Uploader#filename+ is assumed.
#
# === Parameters
#
# [for_file (String)] name of the file <optional>
#
# === Returns
#
# [String] the store path
#
def store_path(for_file=filename) # DEFAULT argument is filename - you don't need to override both
File.join([store_dir, full_filename(for_file)].compact)
end
Run Code Online (Sandbox Code Playgroud)
文件平等:
files_equal?( filename1, filename2 )
return true if File.size(filename1) == File.size(filename2)
# return MD5(filename1) == MD5(filename2)
# as we assume that the filename == MD5 + some suffix :
return File.basename(filename1) == File.basename(filename2) # if names == MD5 are the same
end
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
4905 次 |
| 最近记录: |