Using send_file to download a file from Amazon S3?

前端 未结 7 1576
感动是毒
感动是毒 2020-11-29 18:10

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 somethi

相关标签:
7条回答
  • 2020-11-29 18:33

    How do I allow users to download S3 files?

    If you're able to set some metadata on the file BEFORE you upload it to S3 instead of trying to patch it when the user wants to download it later, then this solution is much simpler:

    https://stackoverflow.com/a/24297799/763231

    If you are using fog then you can do something like this:

    has_attached_file :report,
      fog_file: lambda { |attachment|
        {
          content_type: 'text/csv',
          content_disposition: "attachment; filename=#{attachment.original_filename}",
        }
      }
    

    If you are using Amazon S3 as your storage provider, then something like this should work:

    has_attached_file :report
      s3_headers: lambda { |attachment|
        { 
          'Content-Type' => 'text/csv',
          'Content-Disposition' => "attachment; filename=#{attachment.original_filename}",
        }
      }
    
    0 讨论(0)
  • 2020-11-29 18:36

    def download_pdf @post= @post.avatar.service_url

    send_data(
    
        "#{Rails.root}/public/#{@post}",
        filename: "#{@post}",
        type: "image/*",
        disposition: 'inline', stream: 'true', buffer_size: '4096'
    )
    

    end

    0 讨论(0)
  • 2020-11-29 18:45

    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.

    0 讨论(0)
  • 2020-11-29 18:47

    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)

    0 讨论(0)
  • 2020-11-29 18:54

    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"
    
    0 讨论(0)
  • 2020-11-29 18:56

    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.

    0 讨论(0)
提交回复
热议问题