我的应用程序中有一个下载链接,用户应该能够下载存储在s3上的文件。这些文件可以在类似
的网址上公开访问https://s3.amazonaws.com/:bucket_name/:path/:to/:file.png
下载链接点击我控制器中的操作:
class AttachmentsController < ApplicationController
def show
@attachment = Attachment.find(params[:id])
send_file(@attachment.file.url, disposition: 'attachment')
end
end
但是当我尝试下载文件时出现以下错误:
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'
该文件肯定存在,并且可以在错误消息的URL中公开访问。
如何允许用户下载S3文件?
答案 0 :(得分:78)
您也可以使用send_data
。
我喜欢这个选项,因为你有更好的控制力。您没有向s3发送用户,这可能会让某些用户感到困惑。
我只想在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
并添加路线
get "attachments/download"
答案 1 :(得分:29)
要从您的网络服务器发送文件,
您需要从S3下载(请参阅@nzajt's answer)或
你可以redirect_to @attachment.file.expiring_url(10)
答案 2 :(得分:29)
我认为处理此问题的最佳方法是使用过期的S3网址。其他方法有以下问题:
send_data
不会产生预期的“浏览器下载”。download
控制器操作。我的实现如下:
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
<%= link_to 'Download Avicii by Avicii', attachment.download_url %>
就是这样。
如果您仍想出于某种原因继续执行download
操作,请使用此功能:
在attachments_controller.rb
def download
redirect_to @attachment.download_url
end
感谢guilleva的指导。
答案 3 :(得分:5)
我刚刚将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
该文件正保存在attachment
对象的DriveDocument
字段中。
我希望这会有所帮助。
答案 4 :(得分:4)
以下是最终适合我的方式。从S3对象获取原始数据,然后使用send_data
将其传递给浏览器。
使用此处http://docs.aws.amazon.com/AWSRubySDK/latest/AWS/S3/S3Object.html
中的aws-sdk
gem文档
完整控制器方法
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
答案 5 :(得分:0)
def下载_pdf @ post = @ post.avatar.service_url
send_data(
"#{Rails.root}/public/#{@post}",
filename: "#{@post}",
type: "image/*",
disposition: 'inline', stream: 'true', buffer_size: '4096'
)
结束
答案 6 :(得分:0)
如何允许用户下载S3文件?
如果您可以在将文件上传到S3之前在文件上设置一些元数据,而不是在用户以后想要下载文件时尝试对其进行修补,则此解决方案要简单得多:
https://stackoverflow.com/a/24297799/763231
如果您使用的是
fog
,则可以执行以下操作:has_attached_file :report, fog_file: lambda { |attachment| { content_type: 'text/csv', content_disposition: "attachment; filename=#{attachment.original_filename}", } }
如果您将Amazon S3用作存储提供商,那么 这样应该可以工作:
has_attached_file :report s3_headers: lambda { |attachment| { 'Content-Type' => 'text/csv', 'Content-Disposition' => "attachment; filename=#{attachment.original_filename}", } }