Rails 6,无法让 s3_direct_upload gem 上传,查看正常
Rails 6, can not get s3_direct_upload gem to UPLOAD, view works fine
我有 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?
我得到了文件 select window,我选择了文件名,它显示了文件名,但它并没有开始上传并显示进度条,就好像我什么也没做一样那一点。没有错误,没有任何我能找到的地方。当我并排放置原始应用程序时,我应该会看到一个快速进度条出现然后消失,页面刷新并显示新文件。在我重写的 2 个应用程序中,它永远不会通过文件 select 并显示我 select 编辑的文件名。我将展示一般文件,以便至少可以看到:
所以这是问题 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)
paperclip.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:(如果有人想查看整个 gem 文件,请告诉我)
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。 (我什至尝试转换为 strait 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 天内找不到的配置更改。
任何帮助将不胜感激,除了图片上传之外,我还有其他所有工作都在这 2 个应用程序上工作。
谢谢,
斯科特
我可以确认您是否拉取了最新版本的 s3_direct_upload gem 它实际上使用 Rails 6、aws-sdk-v1 和 Paperclip 正确上传到 Amazon S3 .
为此,您必须将 s3_direct_upload 作为插件而不是 GEM 拉取,您可以将其放入 gem 文件中:
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。
我有 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?
我得到了文件 select window,我选择了文件名,它显示了文件名,但它并没有开始上传并显示进度条,就好像我什么也没做一样那一点。没有错误,没有任何我能找到的地方。当我并排放置原始应用程序时,我应该会看到一个快速进度条出现然后消失,页面刷新并显示新文件。在我重写的 2 个应用程序中,它永远不会通过文件 select 并显示我 select 编辑的文件名。我将展示一般文件,以便至少可以看到:
所以这是问题 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)
paperclip.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:(如果有人想查看整个 gem 文件,请告诉我)
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。 (我什至尝试转换为 strait 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 天内找不到的配置更改。
任何帮助将不胜感激,除了图片上传之外,我还有其他所有工作都在这 2 个应用程序上工作。
谢谢, 斯科特
我可以确认您是否拉取了最新版本的 s3_direct_upload gem 它实际上使用 Rails 6、aws-sdk-v1 和 Paperclip 正确上传到 Amazon S3 .
为此,您必须将 s3_direct_upload 作为插件而不是 GEM 拉取,您可以将其放入 gem 文件中:
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。