Download RESTful files with CarrierWave

I am trying to create an API backend for uploading files. I want to be able to upload files with a POST request that contains a Base64 encoded string. The server must decode the string and save the file using CarrierWave. Here is what I still have:

photo.rb:

class Photo include Mongoid::Document include Mongoid::Timestamps mount_uploader :image_file, ImageUploader end 

image_uploader.rb:

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

Rails Console: (Summary)

 ruby-1.8.7-p334 :001 > img = File.open("../image.png") {|i| i.read} => "\377   JFIF\000\001\002\001\000H\000H\000\000\377 Photoshop 3.0\0008BIM\003... ruby-1.8.7-p334 :003 > encoded_img = Base64.encode64 img => 3af8A\nmLpplt5U8q+a7G2... ruby-1.8.7-p334 :005 > p = Photo.new => #<Photo _id: 4e21b9a31d41c817b9000001, created_at: nil, updated_at: nil, _type: nil, user_id: nil, image_file_filename: nil> ruby-1.8.7-p334 :006 > p.user_id = 1 => 1 ruby-1.8.7-p334 :007 > p.image_file = Base64.decode64 encoded_img \255  =\254\200 7u\226   \230 -zh wT\253%    \036Κ‰s\232Is M\215  ΛΏ6\247\256\177... ruby-1.8.7-p334 :008 > p.save => true ruby-1.8.7-p334 :009 > p.image_file.url => nil 

full

The problem seems to be related to the process of converting a string with a Base64 extension to a file. CarrierWave seems to be expecting a File object, and instead I give it a String. So, how do I convert this String to a File object. I would like this conversion to not save anything in the file system, just create an object and let CarrierWave do the rest.

+6
source share
3 answers

CarrierWave also accepts StringIO, but it expects the original_filename method, as it needs it to determine the file name and perform an extension check. How you changed this between Rails 2 and 3, here are both methods:

Rails 2

 io = StringIO.new(Base64.decode64(encoded_img)) io.original_filename = "foobar.png" p.image_file = io p.save 

In Rails 3 you need to create a new class and then manually add original_filename back

 class FilelessIO < StringIO attr_accessor :original_filename end io = FilelessIO.new(Base64.decode64(encoded_img)) io.original_filename = "foobar.png" p.image_file = io p.save 
+24
source

You do not need monkeypatch StringIO or put any of this into your model. You can override the cache! () Method in your bootloader definition. Or you can do it even further and make the module an inclusion for yourself. My file is a serialized string coming from a json document. The past object looks like this: {: filename => 'something.jpg' ,: filedata => base64 string}.

Here is my module:

 module CarrierWave module Uploader module BackboneLink def cache!(new_file=sanitized_file) #if new_file isn't what we expect just jump to super if new_file.kind_of? Hash and new_file.has_key? :filedata #this is from a browser, so it has all that 'data:..' junk to cut off. content_type, encoding, string = new_file[:filedata].split(/[:;,]/)[1..3] sanitized = CarrierWave::SanitizedFile.new( :tempfile => StringIO.new(Base64.decode64(string)), :filename => new_file[:filename], :content_type => content_type ) super sanitized else super end end end end end 

And then I can include it in the bootloader. uploaders / some _uploader.rb:

 class SomeUploader < CarrierWave::Uploader::Base include CarrierWave::Uploader::BackboneLink 
+1
source
 class AppSpecificStringIO < StringIO attr_accessor :filepath def initialize(*args) super(*args[1..-1]) @filepath = args[0] end def original_filename File.basename(filepath) end end 

also see wiki https://github.com/carrierwaveuploader/carrierwave/wiki/How-to%3A-Upload-from-a-string-in-Rails-3

0
source

Source: https://habr.com/ru/post/892902/


All Articles