I'm using dropzone with S3 and carrierwave. I'm able to upload images through Google Chrome, but I can't get it to work with Safari, which is weird.
This is my form
= nested_form_for @trip, html: { multipart: true, id: 'fileupload', class: 'directUpload', data: { 'form-data' => (@s3_direct_post.fields), 'url' => @s3_direct_post.url, 'host' => URI.parse(@s3_direct_post.url).host } } do |f|
.dropzone#imageUpload
= f.simple_fields_for :trip_images, TripImage.new, child_index: TripImage.new.object_id do |ff|
= ff.file_field :photo, class: 'hide form-fields'
= f.button :submit, id: "submit-data"
This is in the Trip controller
def set_s3_direct_post
@s3_direct_post = S3_BUCKET.presigned_post(key: "/uploads/temporary/#{SecureRandom.uuid}/${filename}", success_action_status: '201', acl: 'public-read', content_type: 'image/jpeg')
end
This is TripImage model
class TripImage < ActiveRecord::Base
belongs_to :resource, :polymorphic => true
mount_uploader :photo, PhotoUploader
after_create :process_async
def to_jq_upload
{
'name' => read_attribute(:attachment_file_name),
'size' => read_attribute(:attachment_file_size),
'url' => attachment.url(:original),
'thumbnail_url' => attachment.url(:thumb),
'delete_url' => "/photos/#{id}",
'delete_type' => 'DELETE'
}
end
private
def process_async
PhotoVersioningJob.set( wait: 5.seconds ).perform_later(self.id)
end
end
This is js
$(function(){
$('.directUpload').find(".dropzone").each(function(i, elem) {
s3ImageUpload(elem);
});
})
function s3ImageUpload(elem){
var fileInput = $(elem);
var form = $(fileInput.parents('form:first'));
var form_url = form.data('url');
var form_data = form.data('form-data');
Dropzone.options.imageUpload = {
url: form_url,
params: form_data,
uploadMultiple: false,
addRemoveLinks: true,
removedfile: function(file){
//some codes
},
success: function(file, serverResponse, event){
//some codes
},
error: function(data){
//some codes
}
};
}
EDIT: Current CORS configuration
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*.example.com</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>POST</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>*</AllowedHeader>
<AllowedHeader>origin</AllowedHeader>
</CORSRule>
</CORSConfiguration>
Tested and doesn't work
EDIT: I also have S3 direct upload, not sure if this affects it too?
S3DirectUpload.config do |c|
c.access_key_id = Rails::AWS.config['access_key_id'] # your access key id
c.secret_access_key = Rails::AWS.config['secret_access_key'] # your secret access key
c.bucket = Rails::AWS.config['bucket_name'] # your bucket name
c.region = 's3' # region prefix of your bucket url. This is _required_ for the non-default AWS region, eg. "s3-eu-west-1"
end
I have run into a similar issue with Safari recently, and discovered that it is sending an extra Access-Control-Request-Header that Chrome does not -- specifically 'origin'. To address this difference I needed to update my AWS CORS config on the destination bucket.
AWS Documentation on the necessity of request headers matching an allowed header config. The third bullet point makes this requirement explicit:
Every header listed in the request's Access-Control-Request-Headers header on the preflight request must match an AllowedHeader element.
This helpful StackOverflow answer gives an example config:
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>Authorization</AllowedHeader>
<AllowedHeader>x-requested-with</AllowedHeader>
</CORSRule>
</CORSConfiguration>
And what needed to be added to get it working in Safari:
<AllowedHeader>origin</AllowedHeader>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With