我添加了通过Dropbox Chooser将文件从Dropbox上传到我的网站的功能。
一切正常,除了一件事 - 我不知道如何正确实现Cancel
功能。它应该以这种方式工作 - 当您点击Cancel
时 - 应从UI中删除相应的文件面板,并停止从Dropbox上传。
当用户点击Choose from Dropbox
并选择文件并点击Submit
时,我向Rails发起Ajax
个请求,方法add_file_via_dropbox
。在此方法中,我通过URL
gem的帮助将Dropbox文件的Amazon S3
上传到Paperclip
服务器。
当用户点击Cancel
时,我想删除部分上传到S3
的文件,该文件将在content.attachment
属性中存储(成功上传后)。但是当他点击Cancel
时 - 文件仍在上传(否则他将看不到Cancel
链接),我不知道如何立即删除它。
我的另一个想法是,我可以简单地将cancelled
属性添加到content
,然后不显示任何content
这样的属性== true
。但是这种方法不会让我免于在Amazon S3
上浪费空间,所以我应该每天运行一些后台任务来删除cancelled
个附件。
我宁愿不首先将它们保存在S3
上。可能吗?我考虑过将控制器的操作add_file_via_dropbox
移动到后台作业,这样一旦我收到来自客户端的kill
ajax请求,我就可以cancel
。我对这一切感到有些困惑。你会如何解决这个问题?感谢。
product_form.html.erb
$.ajax({
// Cancel file uploading on client side via jqXHR.abort()
// It's quite useless because with 99% probability that request
// already was sent to Rails and is processing by appropriate action
beforeSend: function(jqXHR, options) {
tmpl.find('a').click(function(e) {
e.preventDefault();
jqXHR.abort();
$(this).parents('li').remove();
});
},
type: "POST",
dataType: "json",
url: "<%= add_file_via_dropbox_url %>",
data: { product_id: $("#fileupload").data("product_id"), file: dropbox_file },
})
// When Rails response is returned - update UI with "successful upload state"
.done(function(json_file) {
var done_tmpl = $(tmpl("template-download", json_file));
var li = $(".files_list").find('[data-uuid="' + json_file.uuid + '"]');
li.replaceWith(done_tmpl);
}
})
product_controller.rb
# This method is called by Ajax request
def add_file_via_dropbox
product = Product.find(params[:product_id])
# Each Product has_many Contents(files)
file = params[:file]
content = product.contents.build
content.attachment_remote_url = file[:url]
content.save
# Construct json response object for Ajax call
json_obj = []
json_obj << {name: content.attachment_file_name,
size: content.attachment_file_size,
url: content.attachment.url,
thumbnailUrl: content.attachment.url,
deleteUrl: "#{root_url}profile/products/delete_content/#{product.id}/#{content.id}",
deleteType: "DELETE",
uuid: file[:uuid]}
respond_to do |format|
format.json { render json: json_obj }
end
end
content.rb
class Content
attr_reader :attachment_remote_url
has_attached_file :attachment, bucket: ENV['S3_BUCKET_NAME']
def attachment_remote_url=(url_value)
self.attachment = URI.parse(url_value)
end
end
稍后添加
我详细研究了Paperclip的工作原理:
1)当这行代码执行时
content.attachment_remote_url = file[:url]
此回形针代码从paperclip/.../uri_adapter.rb
开始执行
哪个从给定的URL下载文件(在我的示例中为Dropbox URL)并将其保存在本地(在Rails服务器的临时文件中)
class UriAdapter < AbstractAdapter
def initialize(target)
@target = target
@content = download_content # <----
cache_current_values
@tempfile = copy_to_tempfile(@content)
end
...
def download_content
open(@target) # method from 'open-uri' library
end
2)仅当我在此处保存模型时,此文件才会被推送到S3:
content.attachment_remote_url = file[:url]
content.save # <----
将调用Paperclip save
方法:(paperclip/.../attachment.rb
)
def save
flush_deletes unless @options[:keep_old_files]
flush_writes # <-----
@dirty = false
true
end
然后flush_writes
将本地文件推送到S3(paperclip/.../s3.rb
)
def flush_writes
# omitted code
s3_object(style).write(file, write_options) # method from `aws-sdk` gem
# omitted code
end
因此,我将原来的问题缩小到这两个:
1)当open(@target)
已经运行(文件正在下载到我的Rails服务器)时,如何取消对s3_object(style).write(file, write_options)
的呼叫
2)当文件从我的Rails服务器上传到S3时,如何取消对{{1}}的调用?
答案 0 :(得分:2)
如果在服务器端将文件处理为S3之前文件仍在上传到您的服务器,那么您将要像您一样中止连接。即How to cancel/abort jQuery AJAX request?
如果文件已经上传到服务器并且现在正在上传到S3:因为ruby不是基于异步的,所以你基本上必须让文件上传,但是因为服务器现在正在上传它,客户端可以在技术上离开页面。所以:当您的服务器收到文件时,我会传回一个唯一的ID,如果用户仍然点击取消,然后重新拍摄该ID并让您的服务器进行轮询,或者将cron删除。