Downloading files from Paperclip - ruby-on-rails

I have a controller action that is meant to send a file to the user for download from my bucket in S3.
Here's the controller code:
send_file #project.file.url, :type => #project.file_content_type
Here's the error:
Cannot read file http://s3.amazonaws.com/bucket/projects/1/project.xlsx?2011
When I go to the URL directly, I get a download of the file! What's going on?

Is it ok if you just redirect the user to the file on S3?
redirect_to #project.file.url
The issue is that send_file expects a path to a local file, which is then used by the webserver to serve up data from the local file it can access on disk. The file on S3 is only accessible by HTTP, so your webserver can't serve it. To use send_file you'd have to download it and then serve it I think.

Related

How to attach files, which were saved in DriveHQ in Rails mailer?

In my application i have a file upload option. The uploaded files used to saved in DriveHQ ftp server. After uploading i want to send a mail to the admin with the uploaded file as attachment.
I tried as follows
uri = URI::FTP.build(['username:password', 'ftp.drivehq.com', nil,"\\My Documents\\#{17}\\Fitness.txt", 'i'])
And in the mailer:
attachments['image'] = {mime_type: 'text/plain',content: File.read(uri)}
But its not working. it was returning error as
bad component(expected relative path component): \My Documents\17\Fitness.txt;type=i
I guess you're using the API in a wrong way.
You need to download the file, and yes you do it by creating an URI to the FTP server, but then you need to download the file to a temporary directory.
After that, in your mailer you read that file.
Remember since File is a subclass of IO and it does not have the read method, when you invoke File.read, you are actually calling IO.read.

Using Prawn on Heroku

We are currently working on a Rails application hosted on Heroku. We are trying to generate a PDF and push it to the user to download.
We are using Prawn to handle the PDF generation.
Our code for generating the PDF is currently:
Prawn::Document.generate #name[0]+ ".pdf" do
Followed by all of our code to generate the document. Unfortunately, this saves the document to the disk which is not possible (to the best of my knowledge) for applications hosted on Heroku.
We then push it to the user using
send_file "#{Rails.root}/"+#name[0]+ ".pdf", :type =>
'application/pdf',:filename => #name[0]+ ".pdf"
Is there any way using Prawn to directly push the download of the document to the user without saving the document to disk first? If not, are there any other gems for generating PDFs that don't require saving the file to the disk prior to sending the file?
Though this was answered long ago, I'll post for others who may want to do this.
You can also call render with no file name in current Prawn v0.13.2. A string will be returned, which can be sent to the client with send_data. The pattern is:
pdf = Prawn::Document.new
# ... calls to build the pdf
send_data pdf.render,
type: 'application/pdf',
filename: 'download_filename.pdf',
disposition: :inline
This will display the PDF in the browser. If you want instead to have the user download it, omit , disposition: :inline
Of course you only want to do this if the document is reasonably short or your system is not heavily used because it will consume RAM until the user's download is complete.
On Aspen/Bamboo, you can save the file to disk in the tmp/ directory in your application directory (possibly Rails.root.join("tmp")) or any subdirectory.
On Cedar, you can save the file to disk anywhere in your application directory, but you should still choose a subdirectory of your application's tmp/ directory anyway.
In either case, saved files are ephemeral. They are not shared between two running instances of your application; they are not kept between restarts; etc. Do not rely on saving the file in one request and then being able to access it in a second request.

Carrierwave + Fog(s3). Letting the users to download the file

I am working on a project where I have to provide download links to user for the files which are stored in the s3. Initially I tried,
link_to "Download", #medium.file.url
But this opens the file directly on the browser. When i tried to download an mp4 file, chrome started playing it automatically. I don't want that to happen. So I am using send_file for this task,
def download
#medium = Medium.find(params[:id])
send_file #medium.file.url
end
In my local, I have set the storage to file and I have tested this, which works perfectly fine. But on staging, the files are served from s3, I am always getting ActionController::MissingFile. My app is hosted on heroku. I also want to know if using send_file is good choice or if there is a better way of doing this.
config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect'
When i was googling, i found that nginx header setting for sending files should be enabled for production. I added the following line in config/environments/production.rb. Still no luck. I need some help on this. Thanks.
I think this is because S3 wants the file to be played.
I don't have access to my S3 here, but I solved the problem by changing the action for PDF files (which was shown my case) in the S3 control panel.
If you can fix this, I think you can avoid using send_file completely.
Edit: I managed to access S3 now. Go to properties -> Metadata, and add the key
Content-Disposition: Attachment
Then your file will always be downloaded instead of shown.

Download file on click - Ruby on Rails

My application is using Rails 2 backend, Heroku for hosting, Paperclip for file uploads, and Amazon S3 for file storage.
Right now users can upload files with paperclip + s3 - this works flawlessly. After upload, an icon appears on their dashboard, linked to the file location (in s3 bucket). When the icon is clicked, the browser opens the file in a new window (for most file types - PDF, MP3, img, etc). Instead of opening, I want the file to be automatically downloaded when the user clicks the file's icon (like Gmail attachments). The solution should be able to work for any file type and cross-browser.
Is there a helper to do this in rails, or is javascript needed? I'm really stuck on this one so anything to point me in the right direction would be greatly appreciated. Thanks!
Please try the following:
class Test < ActiveRecord::Base
has_attached_file :testfile,
:storage => :s3,
# All your S3 config
:s3_headers => {"Content-Disposition" => "attachment"}
end
This should tell the Paperclip Gem to set the "Content-Disposition" header to the value "attachment" for newly uploaded files.
Note that you have to manually edit the already uploaded file, e.g. with Cyberduck or another FTP Client.
When you transfer the file, you need to set a Content-Disposition header with a value of attachment; filename=yourfilename.pdf. If it's transfered directly from S3, you'll need to tell S3 to set the Content-Disposition headers as well. Possibly also Content-Type.
Note that if you tell S3 to associate a Content-Disposition header, it will always transmit this header.
FWIW, here's Amazon's documentation on doing a PUT for an Object: http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTObjectPUT.html

Ruby on rails: Image downloads with Authentication/Authorization/Time outs

I'm having few doubts on implementing file downloads. I'm creating an app where I use attachment_fu with Amazon s3 to upload files. Things are working pretty well so far on uploading side. Now its the time to start the file downloads. Here is what I need, a logged in user search and browse for Images and they should able to add the files in to a download basket (Let's say its a Download Shopping Cart). Finally the user should be able to download these file(s) from S3 probably as a zipped file.
Is there any plugin/gem where I can use for this?
The downside of giving the customer a zip file of all the files is that you'll need to first pull all of the files from S3 back onto your server, then zip them.
You can certainly do that if you want, but it will take a bit of time, you would not want to do it synchronously as part of the browser request. Instead, do it as a background job using delayed_job or similar.
To do the actual zipping, use Zlib::GzipWriter See http://ruby-doc.org/core/classes/Zlib/GzipWriter.html -- it is part of standard Ruby
You could then:
email the user the actual zip file as an attachment
email the user the link to the zip file on your server
or upload the zip file to s3, then email a link to the zip file on s3
Remember to create a clean up task/job to remove the old zip files from your system...
Alternative is to not zip the files together, instead, give the user one or more links to download the files separately.
S3 enables you to create a url to an S3 file that can be used for a set period of time. (The file would be private on S3 so a straight link to it won't work.) Here's how to create it using attachment-fu and aws-s3 gem:
# I added this as a method to my model for the files stored in S3
def authenticated_s3_url
# return a publicly usable url
connect_to_aws # a local method which connects/re-connects to s3
S3Object.url_for(full_filename,
bucket_name,
:expires_in => 60 * 60) # 1 hour
end

Resources