1

I am sort of new to rails and I am trying to upload images directly to S3 with Shrine. I got direct uploads to S3 to work perfectly, however, when I introduced jquery file upload and upload an image, chrome console throws this error at me. I'm not sure what I'm doing wrong and I can't seem to find a solution anywhere online. I get that it's a presign error and it's probably not finding the cache link but I don't know how to resolve that.

EDIT: This was solved by including the presign code in the Routes file and altering the storage location in the uploads.js to the correct location. Now, however, I have an issue with the files being rolled back when they attempt to upload.

I'm using the cloud based ide C9,

This is my uploads.js file:

$(document).on("turbolinks:load", function(){
$("[type=file]").fileupload({
  add: function(e, data) {
      console.log("add", data);
      data.progressBar = $('<div class="progress"><div class="determinate" 
style="width: 70%"></div></div>').insertBefore("form")
      var options = {
          extension: data.files[0].name.match(/(\.\w+)?$/)[0], //set the 
file extention
         _: Date.now() //prevent caching
      };

      $.getJSON("/autos/upload/cache/presign", options, function(result) {
          console.log("presign", result);
          data.formData = result['fields'];
          data.url = result['url'];
          data.paramName = "file";
          data.submit()
      });

  },
  progress: function(e, data) {
  console.log("progress", data);
  var progress = parseInt(data.loaded / data.total * 100, 10);
  var percentage = progress.toString() + '%'
  data.progressBar.find(".progress-bar").css("width", 
percentage).html(percentage);
  },
  done: function(e, data) {
  console.log("done", data);
  data.progressBar.remove();


  var image = {
    id:       data.formData.key.match(/cache\/(.+)/)[1], // we have to 
remove the prefix part
    storage:  'cache',
    metadata: {
      size:      data.files[0].size,
      filename:  data.files[0].name.match(/[^\/\\]+$/)[0], // IE return full 
path
      mime_type: data.files[0].type
    }
  }
  form = $(this).closest("form");
  form_data = new FormData(form[0]);
  form_data.append($(this).attr("name"), JSON.stringify(image))

  $.ajax(form.attr("action"), {
    contentType: false,
    processData: false,
    data: form_data,
    method: form.attr("method"),
    dataType: "json"
    }).done(function(data) {
        console.log("done from rails", data);
        });
  }
  }); 
});

My routes.rb file includes:

mount ImageUploader::UploadEndpoint => "/images/upload"

mount Shrine.presign_endpoint(:cache) => "/autos/upload/cache/presign"

I have a model which accepts these images as well as other fields called Autos, this is included in the Autos file:

include ImageUploader[:image]

My Autos Controller is:

class AutosController < ApplicationController
  before_action :find_auto, only: [:show, :edit, :update, :destroy]
  def index
    @autos = Auto.all.order("created_at DESC")
  end

  def show
  end

  def new
    @auto = current_user.autos.build
  end

  def create
    @auto = current_user.autos.build(auto_params[:auto])

    if @auto.save
      flash[:notice] = "Successfully created post."
      redirect_to autos_path
    else
      render 'new'
    end
  end

  def edit
  end

  def update
    if @auto.update(auto_params[:auto])
      flash[:notice] = "Successfully updated post."
      redirect_to auto_path(@auto)
    else
      render 'edit'
    end
  end

  def destroy
    @auto.destroy
    redirect_to autos_path
  end

  private 

  def auto_params
    params.require(:auto).permit(:title, :price, :description, :contact, :image, :remove_image)
  end

  def find_auto
    @auto = Auto.find(params[:id])     
  end
end
Uncle Hank
  • 15
  • 1
  • 5
  • did you read http://shrinerb.com/rdoc/files/doc/direct_s3_md.html and what instructions are you using? – Fabrizio Bertoglio Nov 08 '17 at 08:35
  • @FabrizioBertoglio I did read it but I get lost around manually constructing Shrine's JSON representation of an uploaded file and the presign area seems to not work entirely. I am following the GoRails Direct Uploads to S3 tutorial. – Uncle Hank Nov 12 '17 at 18:19

2 Answers2

1

Assuming your image_uploader.rb has the ImageUploader class defined and given that your presign endpoint is something like /autos/upload/cache/presign, your routes.rb should have the presign route defined like so:

mount ImageUploader.presign_endpoint(:cache) => '/autos/upload/cache/presign'

I hope this single change in the route file would make you able to get the presign object that should contain 3 keys: url, fields and headers

# GET /autos/upload/cache/presign
{
  "url": "https://my-bucket.s3-eu-west-1.amazonaws.com",
  "fields": {
    "key": "cache/b7d575850ba61b44c8a9ff889dfdb14d88cdc25f8dd121004c8",
    "policy": "eyJleHBpcmF0aW9uIjoiMjAxNS0QwMToxMToyOVoiLCJjb25kaXRpb25zIjpbeyJidWNrZXQiOiJzaHJpbmUtdGVzdGluZyJ9LHsia2V5IjoiYjdkNTc1ODUwYmE2MWI0NGU3Y2M4YTliZmY4OGU5ZGZkYjE2NTQ0ZDk4OGNkYzI1ZjhkZDEyMTAwNGM4In0seyJ4LWFtei1jcmVkZW50aWFsIjoiQUtJQUlKRjU1VE1aWlk0NVVUNlEvMjAxNTEwMjQvZXUtd2VzdC0xL3MzL2F3czRfcmVxdWVzdCJ9LHsieC1hbXotYWxnb3JpdGhtIjoiQVdTNC1ITUFDLVNIQTI1NiJ9LHsieC1hbXotZGF0ZSI6IjIwMTUxMDI0VDAwMTEyOVoifV19",
    "x-amz-credential": "AKIAIJF55TMZYT6Q/20151024/eu-west-1/s3/aws4_request",
    "x-amz-algorithm": "AWS4-HMAC-SHA256",
    "x-amz-date": "20151024T001129Z",
    "x-amz-signature": "c1eb634f83f96b69bd675f535b3ff15ae184b102fcba51e4db5f4959b4ae26f4"
  },
  "headers": {}
}

When upload starts, you will now find this object in developer console instead of the previous 404 not found error.


UPDATE

I think you are very close to the solution. In your create/update actions, use auto_params[:auto] instead of auto_params

You would also like to check the RoR guide on Association Basics for collection methods

Community
  • 1
  • 1
Wasif Hossain
  • 3,900
  • 1
  • 18
  • 20
  • Thanks for the advice, but it seems to not work. I am still getting the 404 error. I have changed it to just mount ImageUploader.presign_endpoint(:cache) => '/presign' as well and that does not work. Everything you said is in place but it is still returning that error – Uncle Hank Nov 12 '17 at 18:20
  • in your `uploads.js`, if you use `$.getJSON("/autos/upload/cache/presign", options, function(result) {}`, then you must define the route that will lead requests to `/autos/upload/cache/presign`; not merely `/presign`. I hope you get this logic right. There may be other issues that is resulting in 404 still now. Can you please suggest some other means where we can resolve the issue in an interactive way? – Wasif Hossain Nov 13 '17 at 07:42
  • Hey thanks agian, I managed to solve the cache issue just before reading your solution, it was exactly what you said there was an error in the location of my routes.rb presign. I now have another issue. I added a piece of code to my uploads.js file which now rollbacks the picture when it gets halfway uploaded. As for other means to communicate do you have discord? – Uncle Hank Nov 15 '17 at 02:39
  • would you please update `uploads.js` so that I can take a look at the new snippet that might be responsible for the new issue? – Wasif Hossain Nov 15 '17 at 06:50
  • when you submit ajax in the final part, can you see the form data being submitted in rails server log? – Wasif Hossain Nov 16 '17 at 20:04
  • please share the rollback log too. may be you are missing to permit any required params in the controller action. – Wasif Hossain Nov 16 '17 at 20:11
  • moreover, you can safely remove `mount ImageUploader::UploadEndpoint => "/images/upload"` from the routes file. Presign endpoint route will do the job alone. – Wasif Hossain Nov 16 '17 at 20:13
  • lastly if you find this answer worked for you, please accept the answer so that others can trust it too :) – Wasif Hossain Nov 16 '17 at 20:14
  • Thanks again, I have a Users model with devise could this be causing the issue? Right now once the image is chosen, it creates the cache file and uploads it but that's it nothing else. [Here is the output on image submission](https://i.imgur.com/EmKNaW1.png) It submits the form to the listing page but without the image. – Uncle Hank Nov 19 '17 at 23:19
  • would you please append the `AutosController#create` action in your question along with strong param definition that you might have used in `create`? – Wasif Hossain Nov 20 '17 at 04:29
  • I added the entire Autos controller if that would lend any assistance – Uncle Hank Nov 20 '17 at 13:26
  • Please check my updated answer. I hope now it would work – Wasif Hossain Nov 20 '17 at 15:13
  • I made the changes, which can also be seen in the updated controller. I still get the rollback like before, but now on submission of the form it loops back to an empty form and throws back my flash notifications saying that every field is empty. And the form is not submitted to the show page. Any idea what may be causing that? – Uncle Hank Nov 21 '17 at 13:52
0

I think you following the tutorial of gorails direct upload s3 in you gem file make sure you use the right roda version gem 'roda', "~> 2.29.0"

Nejmeddine Jammeli
  • 1,011
  • 9
  • 17