Ruby-on-rails 使用 send_file 从 Amazon S3 下载文件?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12277971/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Using send_file to download a file from Amazon S3?
提问by David Tuite
I have a download link in my app from which users should be able to download files which are stored on s3. These files will be publicly accessible on urls which look something like
我的应用程序中有一个下载链接,用户应该可以从中下载存储在 s3 上的文件。这些文件将在看起来像的 url 上公开访问
https://s3.amazonaws.com/:bucket_name/:path/:to/:file.png
The download link hits an action in my controller:
下载链接在我的控制器中点击了一个动作:
class AttachmentsController < ApplicationController
def show
@attachment = Attachment.find(params[:id])
send_file(@attachment.file.url, disposition: 'attachment')
end
end
But I get the following error when I try to download a file:
但是当我尝试下载文件时出现以下错误:
ActionController::MissingFile in AttachmentsController#show
Cannot read file https://s3.amazonaws.com/:bucket_name/:path/:to/:file.png
Rails.root: /Users/user/dev/rails/print
Application Trace | Framework Trace | Full Trace
app/controllers/attachments_controller.rb:9:in `show'
The file definitely exists and is publicly accessible at the url in the error message.
该文件肯定存在并且可以通过错误消息中的 url 公开访问。
How do I allow users to download S3 files?
如何允许用户下载 S3 文件?
采纳答案by sumskyi
In order to send a file from your web server,
为了从您的网络服务器发送文件,
you need to download it from S3 (see @nzajt's answer) or
you can
redirect_to @attachment.file.expiring_url(10)
您需要从 S3 下载它(请参阅@nzajt 的回答)或
你可以
redirect_to @attachment.file.expiring_url(10)
回答by nzajt
You can also use send_data.
您也可以使用send_data.
I like this option because you have better control. You are not sending users to s3, which might be confusing to some users.
我喜欢这个选项,因为你有更好的控制。您没有将用户发送到 s3,这可能会让某些用户感到困惑。
I would just add a download method to the AttachmentsController
我只想添加一个下载方法 AttachmentsController
def download
data = open("https://s3.amazonaws.com/PATTH TO YOUR FILE")
send_data data.read, filename: "NAME YOU WANT.pdf", type: "application/pdf", disposition: 'inline', stream: 'true', buffer_size: '4096'
end
and add the route
并添加路线
get "attachments/download"
回答by Joshua Pinter
Keep Things Simple For The User
为用户保持简单
I think the best way to handle this is using an expiring S3 url. The other methods have the following issues:
我认为处理这个问题的最好方法是使用过期的 S3 url。其他方法存在以下问题:
- The file downloads to the server first and then to the user.
- Using
send_datadoesn't produce the expected "browser download". - Ties up the Ruby process.
- Requires an additional
downloadcontroller action.
- 文件先下载到服务器,然后再下载到用户。
- 使用
send_data不会产生预期的“浏览器下载”。 - 捆绑 Ruby 进程。
- 需要额外的
download控制器操作。
My implementation looks like this:
我的实现是这样的:
In your attachment.rb
在你的 attachment.rb
def download_url
S3 = AWS::S3.new.buckets[ 'bucket_name' ] # This can be done elsewhere as well,
# e.g config/environments/development.rb
url_options = {
expires_in: 60.minutes,
use_ssl: true,
response_content_disposition: "attachment; filename=\"#{attachment_file_name}\""
}
S3.objects[ self.path ].url_for( :read, url_options ).to_s
end
In your views
在你看来
<%= link_to 'Download Avicii by Avicii', attachment.download_url %>
That's it.
就是这样。
If you still wanted to keep your downloadaction for some reason then just use this:
如果您download出于某种原因仍想保留您的操作,请使用以下命令:
In your attachments_controller.rb
在你的 attachments_controller.rb
def download
redirect_to @attachment.download_url
end
Thanks to guillevafor his guidance.
感谢guilleva的指导。
回答by David Morrow
The following is what ended up working well for me. Getting the raw data from the S3 object and then using send_datato pass that on to the browser.
以下是最终对我有用的内容。从 S3 对象获取原始数据,然后将send_data其传递给浏览器。
Using the aws-sdkgem documentation found here http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/S3/S3Object.html
使用aws-sdk此处找到的gem 文档http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/S3/S3Object.html
full controller method
全控制器方法
def download
AWS.config({
access_key_id: "SECRET_KEY",
secret_access_key: "SECRET_ACCESS_KEY"
})
send_data(
AWS::S3.new.buckets["S3_BUCKET"].objects["FILENAME"].read, {
filename: "NAME_YOUR_FILE.pdf",
type: "application/pdf",
disposition: 'attachment',
stream: 'true',
buffer_size: '4096'
}
)
end
回答by Kenneth John
I have just migrated my public/systemfolder to Amazon S3. Solutions above help but my app accepts different kinds of documents. So if you need the same behavior, this helps for me:
我刚刚将我的public/system文件夹迁移到 Amazon S3。上述解决方案有帮助,但我的应用程序接受不同类型的文档。因此,如果您需要相同的行为,这对我有帮助:
@document = DriveDocument.where(id: params[:id])
if @document.present?
@document.track_downloads(current_user) if current_user
data = open(@document.attachment.expiring_url)
send_data data.read, filename: @document.attachment_file_name, type: @document.attachment_content_type, disposition: 'attachment'
end
The file is being saved in the attachmentfield of DriveDocumentobject.
I hope this helps.
该文件正在保存在对象attachment字段中DriveDocument。我希望这有帮助。

