Rails 使用 CarrierWave 实现字符串方式的文件上传

zzxworld · 2017年03月21日 · 最后由 zzxworld 回复于 2017年03月21日 · 2057 次阅读

在 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)
File.open('somewhere') do |f|
  u.avatar = f
end

官网文档时这样写的

dylin 回复

没错,但这样也可以喔,不信你试试。

u.avatar = File.open('somewhere')
需要 登录 后方可回复, 如果你还没有账号请 注册新账号