title: Uploading Base64 image data to S3 via AWS Ruby SDK
body: <p>I've got a drag and drop function which takes the file that's been dropped on it and converts it to Base64 data. Before, it was uploading to Imgur, whose API supports Base64 uploads, and now I'm working on moving to Amazon S3. </p>
  
  <p>I've seen <a href="https://stackoverflow.com/questions/23557848/upload-base64-image-data-to-amazon-s3">examples of people using XMLHTTP requests</a> and CORS to upload data to S3, I'm using <a href="http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/S3/S3Object.html" rel="nofollow noreferrer">Amazon's AWS S3 SDK gem</a> to avoid having to sign policies and other things, as the gem does that for me. So what I've done is send the Base64 data to a local controller metod which uses the gem to upload to S3. </p>
  
  <p>The other posts using Ajax i've seen show that S3 supports raw data uploads, but the gem doesn't seem to, as whenever I view the uploads i get broken images. Am I uploading it incorrectly? Is the data in the wrong format? I've tried the basic Base64, atob Base64, and blob urls, but nothing works so far. </p>
  
  <p>JS:</p>
  
  <pre><code>fr.onload = function(event) {
          var Tresult = event.target.result;
          var datatype = Tresult.slice(Tresult.search(/\:/)+1,Tresult.search(/\;/));
          var blob = atob(Tresult.replace(/^data\:image\/\w+\;base64\,/, ''));
          $.ajax({
              type:"POST",
              data:{
                  file:blob,
                  contentType: datatype,
                  extension:datatype.slice(datatype.search(/\//)+1)
              },
              url:'../uploads/images',
              success:function(msg) {
                  handleStatus(msg,"success");
              },
              error:function(errormsg) {
                  handleStatus(errormsg,"error");
              }
          });
      }
  </code></pre>
  
  <p>Controller method:</p>
  
  <pre><code>def supload
      s3 = AWS::S3.new(:access_key_id =&gt; ENV['S3_KEY'],:secret_access_key =&gt; ENV['S3_SECRET'])
      bucket = s3.buckets['bucket-name']
      data = params[:file].to_s
      type = params[:contentType].to_s
      extension = params[:extension].to_s
      name = ('a'..'z').to_a.shuffle[0..7].join + ".#{extension}"
      obj = bucket.objects.create(name,data,{content_type:type,acl:"public_read"})
      url = obj.public_url().to_s
      render text: url
  end
  </code></pre>
  
  <hr>
  
  <p>Edit:</p>
  
  <p>To be clear, I've tried a couple of different formats, the one displayed above is decoded base64. Regular Base64 looks like this:</p>
  
  <pre><code>        var Tresult = event.target.result;
          var datatype = Tresult.slice(Tresult.search(/\:/)+1,Tresult.search(/\;/));
          var blob = Tresult;
          $.ajax({
              type:"POST",
              data:{
                  file:blob,
                  mimeType: datatype,
                  extension:datatype.slice(datatype.search(/\//)+1)
              },
              url:'../uploads/images',
              success:function(msg) {
                  handleStatus(msg,"success");
              },
              error:function(errormsg) {
                  handleStatus(errormsg,"error");
              }
          });
  </code></pre>
  
  <p>and a blob url looks like this:</p>
  
  <pre><code>var blob = URL.createObjectURL(dataURItoBlob(Tresut,datatype));
  ...
  function dataURItoBlob(dataURI, dataType) {
      var binary = atob(dataURI.split(',')[1]);
      var array = [];
      for(var i = 0; i &lt; binary.length; i++) {
          array.push(binary.charCodeAt(i));
      }
      return new Blob([new Uint8Array(array)], {type: dataType});
  }
  </code></pre>