Using send_file to download a file from Amazon S3?

给你一囗甜甜゛ 提交于 2019-11-27 06:16:07
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)

nzajt

You can also use 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.

I would just add a download method to the 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"
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:

  • The file downloads to the server first and then to the user.
  • Using send_data doesn't produce the expected "browser download".
  • Ties up the Ruby process.
  • Requires an additional download controller action.

My implementation looks like this:

In your 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 download action for some reason then just use this:

In your attachments_controller.rb

def download
  redirect_to @attachment.download_url
end

Thanks to guilleva for his guidance.

I have just migrated my public/system folder 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:

@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 attachment field of DriveDocument object. I hope this helps.

The following is what ended up working well for me. Getting the raw data from the S3 object and then using send_data to pass that on to the browser.

Using the aws-sdk gem documentation found here 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
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!