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
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}", } }
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
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.
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)
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"
I think the best way to handle this is using an expiring S3 url. The other methods have the following issues:
send_data
doesn't produce the expected "browser download".download
controller action.My implementation looks like this:
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 %>
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.