允许用户从S3存储中下载文件

16

目前我正在使用Amazon S3和Paperclip,允许我的用户上传与他们创建的事件相关联的图像。我的最终目标是,既然其他人可以查看此事件,就能够单击该图像并提示将其保存到他们的计算机中。目前,单击链接将在浏览器窗口中打开图像。我更愿意让它要求他们下载。所有图像仅保存在S3上,而不是本地。如果可能的话,需要隐藏暴露的S3 URL或伪装它。

这是我的当前设置

Index.html

<%= link_to 'Download Creative', event.creative.url, class: "btn btn-info" %>

Event.rb

has_attached_file :creative,
                :styles => { :thumb => "150x150", :custcreative => "250x75" },
                :path => ":attachment/:id/:style.:extension",
                :s3_domain_url => "******.s3.amazonaws.com",
                :storage => :s3,
                :s3_credentials => Rails.root.join("config/s3.yml"),
                :bucket => '*****',
                :s3_permissions => :public_read,
                :s3_protocol => "http",
                :convert_options => { :all => "-auto-orient" },
                :encode => 'utf8'
希望有人能帮助我。
5个回答

30
为了减少应用程序的额外负载(节省 Heroku 中 Dyno 的时间),我更愿意像这样做:将此方法添加到您的带有附件的模型中:

为了避免给你的应用程序增加额外的负载(节省Heroku中的Dyno时间),我宁愿采取这样的做法:在你的模型中添加该方法并带上附件:

def download_url(style_name=:original)
  creative.s3_bucket.objects[creative.s3_object(style_name).key].url_for(:read,
      :secure => true,
      :expires => 24*3600,  # 24 hours
      :response_content_disposition => "attachment; filename='#{creative_file_name}'").to_s
end

然后在您的视图/控制器中像这样使用它:

<%= link_to 'Download Creative', event.download_url, class: "btn btn-info" %>

1
太棒了!这个方法非常有效,可以直接从S3下载文件,不会占用Ruby进程,也不需要先下载到服务器再发送给用户。真是太棒了! - Joshua Pinter
此外,它不需要在控制器中执行其他操作。 - Joshua Pinter
1
阅读了许多有关从s3下载文件的答案(send_data和send_file解决方案随处可见),但这是最简洁的,只需最少量的代码即可直接运行。 - Sean Montana
请问您能否解释一下什么是creative和s3_object()?还有style_name是什么意思?实际上,我遇到了一个错误,提示undefined method creative。 - Aniket Tiwari
“creative” 是附件的名称(请参见问题),s3_object 是 Paperclip 方法,用于获取 S3 对象的引用,可选的 style_name 参数仅在您想要创建与原始文件不同版本(通常是缩略图或调整大小的图像)的链接时使用。您必须将“creative”替换为您的附件名称。 - guilleva

17
为了使这个工作,我只是在控制器中添加了一个新的操作,所以在你的情况下它可能是这样的:
#routes
resources :events do
  member { get :download }
end

#index
<%= link_to 'Download Creative', download_event_path(event), class: "btn btn-info" %>

#events_controller
def download
  data = open(event.creative_url)
  send_data data.read, :type => data.content_type, :x_sendfile => true
end

编辑: 下载控制器操作的正确解决方案可以在此处找到(我已更新上面的代码):如何强制链接在下载而不是播放MP3?


你太棒了!我借鉴了这个想法,并稍作修改以适应我的应用程序: - RubyNewbie

3
在aws-sdk v2中,有一个名为:presigned_url的方法被定义在Aws::S3::Object中,您可以使用此方法构建s3对象的直接下载链接。
s3 = Aws::S3::Resource.new
# YOUR-OBJECT-KEY should be the relative path of the object like 'uploads/user/logo/123/pic.png'
obj = s3.bucket('YOUR-BUCKET-NAME').object('YOUR-OBJECT-KEY')
url = obj.presigned_url(:get, expires_in: 3600, response_content_disposition: "attachment; filename='FILENAME'")

在您的视图中,只需使用:

= link_to 'download', url

1
event = Event.find(params[:id])
  data = open(event.creative.url)
  send_data data.read, :type => data.content_type, :x_sendfile => true, :url_based_filename => true
end

0

您需要在HTTP响应头中将"Content-Disposition"设置为"attachment"。我不是Rails开发人员 - 所以只需在Google上搜索,您会看到很多示例 - 但它可能看起来像这样:

    :content_disposition => "attachment"

或者

     ...
    :disposition => "attachment"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接