Rails Carrierwave Base64 图片上传

18

使用Carrierwave从客户端上传图像到Rails后端的最佳方式是什么?目前,我们的iOS开发人员将文件作为base64发送,因此请求会像这样到达:

"image_data"=>"/9j/4AAQSkZJRgABAQAAAQABAAD/4QBYRXhpZgAATU0AKgAAAAgAAgESAAMAAAABAAEAAIdpAAQAAAABAAAAJgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAHqADAAQAAAABAAAAHgAAAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wAARCAAeAB4DAREAAhEBAxEB/8QAHwAAAQUBAQE....

所以,我的问题实际上有两个。我应该告诉他发送不同的文件格式吗?如果base64是发送这些文件的正确方式,那么我该如何在carrierwave中处理它们呢?


iOS应用程序无法发送标准的多部分文件上传POST请求吗? - Tomdarkness
我真的不确定那个。我不会编写iOS代码。 - botbot
我也不确定,但我建议你问问你的iOS开发人员,看看这是否可行。从Rails的角度来看,这似乎是最明智的选择,而不是处理base_64编码数据。 - Tomdarkness
我认为你是对的,我应该问一下,感谢你的建议。 - botbot
3个回答

29

我认为一个解决方案是将解码后的数据保存到文件中,然后将此文件分配给已挂载的上传器。之后可以将该文件删除。

另外一个(内存中)的解决方案可以是这个:

# define class that extends IO with methods that are required by carrierwave
class CarrierStringIO < StringIO
  def original_filename
    # the real name does not matter
    "photo.jpeg"
  end

  def content_type
    # this should reflect real content type, but for this example it's ok
    "image/jpeg"
  end
end

# some model with carrierwave uploader
class SomeModel
  # the uploader
  mount_uploader :photo, PhotoUploader

  # this method will be called during standard assignment in your controller
  # (like `update_attributes`)
  def image_data=(data)
    # decode data and create stream on them
    io = CarrierStringIO.new(Base64.decode64(data))

    # this will do the thing (photo is mounted carrierwave uploader)
    self.photo = io
  end

end

7
我在配置文件中添加了config.filter_parameters += [:password, :image_data],以避免污染日志。 - sites
我尝试了你的代码,但它创建JPEG文件时出现错误。我已经更新了帖子,您能检查一下吗? - santosh
1
我正在使用从canvas生成的data URL。我的最终图像无效。你必须确保传入的数据只是数据,而不包括"data:image/png,"部分。 - Jonathan Allard
大家好.. 当我尝试上述操作时,我遇到了以下错误,我不确定为什么会出现这种情况,错误信息是“Cloudinary :: CarrierWave :: UploadError(无效的图像文件):”。请问有人可以帮助我吗? - ratnakar
我该如何从数据中获取正确的内容类型和真实图像名称(将PNG文件保存为JPEG文件可能会出现问题)?如果它与数据一起提供,我该如何做到这一点? - Almaron
显示剩余4条评论

10
你可以轻松地使用Carrierwave-base64 Gem实现这一点。你不需要自己处理数据,你所需要做的就是添加这个宝石并更改你的模型。
mount_uploader :file, FileUploader

mount_base64_uploader :file, FileUploader

就是这样了,现在你可以轻松地说:

Attachment.create(file: params[:file])

这对我有用,但是花了一段时间才弄清楚如何将图像数据添加到我的控制器中的用户对象中。原始的base64字符串通过“avatar”参数进入控制器,我的用户模型具有一个名为“avatar”的carrierwave base64uploader,因此它看起来像这样:user.update_attributes(avatar: "data:image/png;base64," + params[:avatar])。 - gravy
我需要添加数据前缀。在添加了宝石 "data:image/png;base64," + params[:image_file]之后,它对我有用。谢谢 @gravy - mahfuz

6

虽然这是一个老问题,但我必须做类似的事情,即从通过json请求传递的base64字符串上传图像。这就是我最终采取的方法:

#some_controller.rb
def upload_image
  set_resource
  image = get_resource.decode_base64_image params[:image_string]
  begin
    if image && get_resource.update(avatar: image)
      render json: get_resource
    else
      render json: {success: false, message: "Failed to upload image. Please try after some time."}
    end
  ensure
    image.close
    image.unlink
  end
end

#some_model.rb
def decode_base64_image(encoded_file)
  decoded_file = Base64.decode64(encoded_file)
  file = Tempfile.new(['image','.jpg']) 
  file.binmode
  file.write decoded_file

  return file
end

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接