在 Rails 中使用 CarrierWave 实现常规的上传功能很容易。但如果有了特殊需求时,就需要一些小技巧来解决了。例如我今天遇到的一个问题就是要把存储在 SQLite 数据包中字符串格式的图片数据导入到 Rails 项目的数据库中。
查看 CarrierWave 的文档了解到,使用它关联的模型字段可以接受文件格式的值。例如下面这个用户头像的模型定义:
class User < ActiveRecord::Base
mount_uploader :avatar, AvatarUploader
end
就可以使用打开指定文件的方式赋值:
user = User.new
user.avatar = File.open('/path/avatar.jpg')
但翻遍了文档,并没有发现可以使用字符串的方式赋值。手动实验了一下,证明确实是不可以的。所以只能以文件的方式来解决。
以文件的方式貌似也很好解决。把 SQLite 中字符串格式的图片内容先保存成文件,然后再使用这个存储的文件地址就可以了。如果要简单点,还可以使用 Tempfile
对象。但这不是一个简洁优雅的方式,我希望能够省略掉保存文件的这一步。在翻阅了 CarrierWave 的 Wiki 后,我找到了这篇文章:How to: Upload from a string in Rails 3 or later,这正是我需要的解决方式。按照其中介绍,我也实现了一个自己的 StringFile
类:
class StringFile < StringIO
def initialize(*args)
super(*args[1..-1])
@filename = args[0]
end
def original_filename
@filename
end
end
代码跟 wiki 中的例子基本雷同,但存放的位置不一样。我把这个类放到了 lib 目录中。原因是我只在自定义终端命令中使用它,所以没必要全局加载。最后还是以用户头像的模型举例,它的使用方式如下:
require 'string_file'
user = User.new
user.avatar = StringFile.new('face.jpg', face_raw_string)