Rails 6,无法将 s3_direct_upload gem 上传到 UPLOAD,查看工作正常
Posted
技术标签:
【中文标题】Rails 6,无法将 s3_direct_upload gem 上传到 UPLOAD,查看工作正常【英文标题】:Rails 6, can not get s3_direct_upload gem to UPLOAD, view works fine 【发布时间】:2021-11-28 17:54:38 【问题描述】:我有 2 个应用程序已从旧版本的 Rails(3.2 和 4.2.1)重写为 Rails v6.1.4.1,它们都使用 s3_direct_upload gem。
在这两个应用程序上,我在 Webdev 控制台、Rails 控制台、日志或我能找到的任何地方都没有收到任何错误。在两个应用程序的情况下,存储桶都显示得很好。 我检查了 CORS 设置,一切正常。这两个应用程序目前都在 Heroku 上运行,代码与现在相同,但正在运行。
有谁知道 s3_direct_upload gem 是否真的适用于 Rails 6?
我得到了文件选择窗口,我选择了文件名,它显示了文件名,但它没有开始上传并显示进度条,它就像我当时什么都没做一样。我能找到的任何地方都没有错误。当我将原始应用程序并排放置时,我应该会看到一个快速进度条出现然后消失,页面刷新并显示新文件。在我重写的 2 个应用程序中,它永远不会超过文件选择并显示我选择的文件名。我将显示一般文件,以便至少可以看到:
这就是问题 1,s3_direct_upload gem 在 Rails 6 中工作吗?
以下是所需的基本文件:
s3_direct_upload.rb
S3DirectUpload.config do |c|
c.access_key_id = Rails.configuration.aws[:access_key_id]
c.secret_access_key = Rails.configuration.aws[:secret_access_key]
c.bucket = Rails.configuration.aws[:bucket]
c.region = "ENV['AWS_REGION']"
c.url = "https://#c.bucket.s3.amazonaws.com/"
end
aws.rb
require 'aws-sdk-v1'
# Rails.configuration.aws is used by AWS, Paperclip, and S3DirectUpload
Rails.configuration.aws = YAML.load(ERB.new(File.read("#Rails.root/config/aws.yml")).result)[Rails.env].symbolize_keys!
AWS.config(logger: Rails.logger)
AWS.config(Rails.configuration.aws)
回形针.rb
Paperclip::Attachment.default_options.merge!(
url: ":s3_domain_url",
path: ":class/:attachment/:id/:style/:filename",
storage: :s3,
s3_credentials: Rails.configuration.aws,
s3_permissions: :private,
s3_protocol: "https",
s3_region: ENV["AWS_REGION"]
)
aws.rb
require 'aws-sdk-v1'
# Rails.configuration.aws is used by AWS, Paperclip, and S3DirectUpload
Rails.configuration.aws = YAML.load(ERB.new(File.read("#Rails.root/config/aws.yml")).result)[Rails.env].symbolize_keys!
AWS.config(logger: Rails.logger)
AWS.config(Rails.configuration.aws)
aws.yml(我将存储桶名称更改为 mybucket,图片有效,因此我知道存储桶有效)
defaults: &defaults
development:
<<: *defaults
region: <%=ENV["AWS_REGION"]%>
bucket: "mybucket"
access_key_id: <%=ENV["AWS_ACCESS_KEY_DPFR"]%>
secret_access_key: <%=ENV["AWS_SECRET_KEY_DPFR"]%>
test:
<<: *defaults
region: <%=ENV["AWS_REGION"]%>
bucket: "mybucket-test"
production:
region: <%=ENV["AWS_REGION"]%>
access_key_id: <%=ENV["AWS_ACCESS_KEY_DPFR"]%>
secret_access_key: <%=ENV["AWS_SECRET_KEY_DPFR"]%>
bucket: "mybucket"
以下是相关的 gem:(如果有人想查看整个 gemfile,请告诉我)
gem 'paperclip-aws', '~> 1.6', '>= 1.6.8'
gem 'aws-sdk-v1', '~> 1.67'
gem 's3_direct_upload', '~> 0.1.7'
这里是相关的 js s3_direct_upload.js.coffee。 (我什至尝试转换为海峡 JS 与咖啡并没有区别。警报在那里,因为我想确保它正在读取文件并且它确实收到了警报。
#= require jQuery-fileupload/basic
#= require jQuery-fileupload/vendor/tmpl
alert("We are in the S3_Direct_Upload coffee file");
$ = jQuery
$.fn.S3Uploader = (options) ->
# support multiple elements
if @length > 1
@each ->
$(this).S3Uploader options
return this
$uploadForm = this
settings =
path: ''
additional_data: null
before_add: null
remove_completed_progress_bar: true
remove_failed_progress_bar: false
progress_bar_target: null
click_submit_target: null
allow_multiple_files: true
dropZone: null
$.extend settings, options
current_files = []
forms_for_submit = []
if settings.click_submit_target
settings.click_submit_target.click ->
form.submit() for form in forms_for_submit
false
$wrapping_form = $uploadForm.closest('form')
if $wrapping_form.length > 0
$wrapping_form.off('submit').on 'submit', ->
$wrapping_form.find('.s3_uploader input').prop "disabled", true
true
setUploadForm = ->
$uploadForm.find("input[type='file']").fileupload
dropZone: settings.dropzone_target
add: (e, data) ->
file = data.files[0]
file.unique_id = Math.random().toString(36).substr(2,16)
unless settings.before_add and not settings.before_add(file)
current_files.push data
if $('#template-upload').length > 0
data.context = $($.trim(tmpl("template-upload", file)))
$(data.context).appendTo(settings.progress_bar_target || $uploadForm)
else if !settings.allow_multiple_files
data.context = settings.progress_bar_target
if settings.click_submit_target
if settings.allow_multiple_files
forms_for_submit.push data
else
forms_for_submit = [data]
else
data.submit()
start: (e) ->
$uploadForm.trigger("s3_uploads_start", [e])
progress: (e, data) ->
if data.context
progress = parseInt(data.loaded / data.total * 100, 10)
data.context.find('.bar').css('width', progress + '%')
done: (e, data) ->
content = build_content_object $uploadForm, data.files[0], data.result
callback_url = $uploadForm.data('callback-url')
if callback_url
content[$uploadForm.data('callback-param')] = content.url
$.ajax
type: $uploadForm.data('callback-method')
url: callback_url
data: content
beforeSend: ( xhr, settings ) ->
event = $.Event('ajax:beforeSend')
$uploadForm.trigger(event, [xhr, settings])
return event.result
complete: ( xhr, status ) ->
event = $.Event('ajax:complete')
$uploadForm.trigger(event, [xhr, status])
return event.result
success: ( data, status, xhr ) ->
event = $.Event('ajax:success')
$uploadForm.trigger(event, [data, status, xhr])
return event.result
error: ( xhr, status, error ) ->
event = $.Event('ajax:error')
$uploadForm.trigger(event, [xhr, status, error])
return event.result
data.context.remove() if data.context && settings.remove_completed_progress_bar # remove progress bar
$uploadForm.trigger("s3_upload_complete", [content])
current_files.splice($.inArray(data, current_files), 1) # remove that element from the array
$uploadForm.trigger("s3_uploads_complete", [content]) unless current_files.length
fail: (e, data) ->
content = build_content_object $uploadForm, data.files[0], data.result
content.error_thrown = data.errorThrown
data.context.remove() if data.context && settings.remove_failed_progress_bar # remove progress bar
$uploadForm.trigger("s3_upload_failed", [content])
formData: (form) ->
data = $uploadForm.find("input").serializeArray()
fileType = ""
if "type" of @files[0]
fileType = @files[0].type
data.push
name: "content-type"
value: fileType
key = $uploadForm.data("key")
.replace('timestamp', new Date().getTime())
.replace('unique_id', @files[0].unique_id)
.replace('cleaned_filename', cleaned_filename(@files[0].name))
.replace('extension', @files[0].name.split('.').pop())
# substitute upload timestamp and unique_id into key
key_field = $.grep data, (n) ->
n if n.name == "key"
if key_field.length > 0
key_field[0].value = settings.path + key
# IE <= 9 doesn't have XHR2 hence it can't use formData
# replace 'key' field to submit form
unless 'FormData' of window
$uploadForm.find("input[name='key']").val(settings.path + key)
data
build_content_object = ($uploadForm, file, result) ->
content =
if result # Use the S3 response to set the URL to avoid character encodings bugs
content.url = $(result).find("Location").text()
content.filepath = $('<a />').attr('href', content.url)[0].pathname
else # IE <= 9 retu rn a null result object so we use the file object instead
domain = $uploadForm.find('input[type=file]').data('url')
key = $uploadForm.find('input[name=key]').val()
content.filepath = key.replace('/filename', '').replace('/cleaned_filename', '')
content.url = domain + key.replace('/filename', encodeURIComponent(file.name))
content.url = content.url.replace('/cleaned_filename', cleaned_filename(file.name))
content.filename = file.name
content.filesize = file.size if 'size' of file
content.lastModifiedDate = file.lastModifiedDate if 'lastModifiedDate' of file
content.filetype = file.type if 'type' of file
content.unique_id = file.unique_id if 'unique_id' of file
content.relativePath = build_relativePath(file) if has_relativePath(file)
content = $.extend content, settings.additional_data if settings.additional_data
content
cleaned_filename = (filename) ->
filename.replace(/\s/g, '_').replace(/[^\w.-]/gi, '')
has_relativePath = (file) ->
file.relativePath || file.webkitRelativePath
build_relativePath = (file) ->
file.relativePath || (file.webkitRelativePath.split("/")[0..-2].join("/") + "/" if file.webkitRelativePath)
#public methods
@initialize = ->
# Save key for IE9 Fix
$uploadForm.data("key", $uploadForm.find("input[name='key']").val())
setUploadForm()
this
@path = (new_path) ->
settings.path = new_path
@additional_data = (new_data) ->
settings.additional_data = new_data
@initialize()
我尝试让 webpacker 服务器的 JS 文件没有区别,我开始怀疑 s3_direct_upload gem 不适用于较新的 rails,因为这几乎是唯一的区别,或者需要进行一些配置更改在过去 3 天里我找不到。
任何帮助将不胜感激,除了图片上传之外,我还有 100% 的其他应用程序在这 2 个应用程序上工作。
谢谢你, 斯科特
【问题讨论】:
【参考方案1】:我可以确认您是否提取了最新版本的 s3_direct_upload gem,它确实使用 Rails 6、aws-sdk-v1 和 Paperclip 正确上传到 Amazon S3。
为此,您必须将 s3_direct_upload 作为插件而不是 GEM 拉取,您可以通过将其放入 gemfile 中来做到这一点:
gem 's3_direct_upload', github: 'waynehoover/s3_direct_upload', ref: '6f6decc75fdf89888d7f729fc89f78e90d91cece'
他们修复了一个以 $utf8 开头的密钥的策略问题,该问题导致更新中出现 POST 错误 403 以及其他一些问题。据说要使用最新版本,您还必须在 file_field_tag 中添加一个额外条目。
data: url: s3_uploader_url
例如,我的 file_field_tag 是这样设置的:(我使用 HAML)
= file_field_tag(:file, id: "before_photo", multiple: true, data: url: s3_uploader_url )
使用 GIT 存储库中的最新版本并将 data: 属性添加到 file_field_tag 后,它开始正常工作。上传正在上传到上传存储桶中的 Amazon S3。
【讨论】:
以上是关于Rails 6,无法将 s3_direct_upload gem 上传到 UPLOAD,查看工作正常的主要内容,如果未能解决你的问题,请参考以下文章
Rails 6.1:Heroku 上的作业将使用 Async 而不是 Sidekiq
Heroku 推送错误:“无法检测到 rake 任务”(Rails 6.1)
Rails 5/6:如何在 webpacker 中包含 JS 函数?
Rails 6.1.0 [webpack-cli] TypeError:无法读取未定义的属性“插件”