Ruby Rails 使用 Jquery FileUpload 直接上传 AWS S3

Ruby on Rails Direct AWS S3 Upload with JqueryFileUpload

我想为我的网站构建一个简单的文件上传系统(只有我会访问和上传)来上传我的投资组合页面。我的网站在 Rails 上 Ruby,托管在 Heroku 上。

所以我按照 Heroku Tutorial 将图像上传到 S3。它使用 aws-sdk gem 完成教程后,当我尝试上传一个简单的 .png 文件时,我收到以下错误。

Bad Request 400: Bucket POST must contain a field named 'key'.  If it is specified, please check the order of the fields.

投资组合控制器

 def new
    @s3_direct_post = S3_BUCKET.presigned_post(key: "${filename}", success_action_status: 201, acl: :public_read)
    @portfolio = Portfolio.new()
  end

检查视图中的 javascript formData 值:

...
fileInput.fileupload({
                formData:       '<%=@s3_direct_post.fields.to_json.html_safe %>',
                fileInput:      fileInput,
                url:            '<%=@s3_direct_post.url%>',
                type:           'POST',
                autoUpload:     true,
                paramName:      'file',
                dataType:       'XML',
                replaceFileInput: false,

...

给出:

{
"AWSAccessKeyId"=>"my-access-key",
"key"=>"${filename}",
"policy"=> "long-string",
"signature"=>"randomg-signature-string", 
"success_action_status"=>"201",
"acl"=>"public-read"
}

我已尝试添加以同步我的时间,如 /config/initializers/aws.rb 所示:

AWS.config(access_key_id:     ENV['AWS_ACCESS_KEY_ID'],
           secret_access_key: ENV['AWS_SECRET_ACCESS_KEY'])

AWS::S3.const_set('DEFAULT_HOST', "s3-ap-southeast-1.amazonaws.com")

S3_BUCKET = AWS::S3.new.buckets[ENV['S3_BUCKET']]

查看 Google 和 Whosebug 后,似乎 Jquery 可能正在重建表单数据,因此弄乱了 POST 值的顺序。

问题是,我对 Rails 和 Javascript 上的 Ruby 比较陌生,所以我不确定如何解决这个问题。

如有任何建议,我们将不胜感激。谢谢!

我决定改用 Paperclip Heroku Tutorial,并成功上传到 S3。

希望这对遇到同样问题的人有所帮助。

我最近遇到了同样的问题,这就是解决方案:

你只需要改变这个

formData:  '<%=@s3_direct_post.fields.to_json.html_safe %>'

对此:

formData:  <%=@s3_direct_post.fields.to_json.html_safe %>

因为@s3_direct_post.fields.to_json.html_safe会给你这样的东西:

{"key":"value", "key":"value", "key":"value"}

并通过将其包裹在 ' ' 之间,它会变成这样:

'{"key":"value", "key":"value", "key":"value"}'

这不是有效的 JSON

另一个解决方案(但效率不高,因为我认为第一个更优雅)

通过查看 jquery 文件上传 documentation 它说:

By default, the plugin calls jQuery's serializeArray method on the upload form to gather additional form data for all input fields (including hidden fields)

因此您可以像这样将这些字段添加到表单中(在文件输入之前):

<% @s3_direct_post.fields.map do |name, value| %>
    <input type="hidden" name="<%= name %>" value="<%= value %>" />
<% end %>

<%= f.file_field :avatar_url%>
...
...

但请注意,因为正如文档告诉您的那样,它将收集所有字段,包括隐藏字段(在您的 Rails 应用程序中,有一些额外的隐藏字段,如 utf8 和authenticity_token) 这会给您一个错误,因为 Amazon S3 不会接受它!

这是我用来解决这个问题的小技巧:

创建一个不同于初始表单的单独表单,并为其分配一个 ID,在我的例子中,该 ID 是 fields-for-s3

<form id="fields-for-s3">
    <% @s3_direct_post.fields.map do |name, value| %>
        <input type="hidden" name="<%= name %>" value="<%= value %>" />
    <% end %>
</form>
<%= form_for @user, ..... %>
    ....
<% end %>

然后在表单上使用 jQuery serializeArray() 方法(具有特定 ID)手动创建一个 formData 对象,如下所示:

formData: $('form#fields-for-s3').serializeArray()

希望对您有所帮助。

我运行遇到同样的问题: 你也可以打电话 JSON.parse(表单数据); 来自你的 javascript.