Rails5: Open excel file in browser - ruby-on-rails

I am using shrine for excel file uploading. File is successfully uploaded and linked to model instances using shrine.
I wanted to open that Excel file(.xls, .xlsx) in browser instead of downloading it. I have looked for various solutions and tried them, but no luck.
The recommended solution from most of the people is using 'send_data', I have tried with that also:
send_file(data, type: 'application/vnd.ms-excel', filename: "#{uploaded_file.metadata["filename"]}", disposition: 'inline')
But it is downloading the file instead of opening it directly in browser.
My questions are
1) Is this opening/downloading file depends on browser settings?
2) Which one is better? To open a file in browser OR use gem like 'axlsx' to create and render excel templates in app?
Thanks!

Whether the browser will attempt to open the file in the browser or download it is determined by the Content-Disposition response header.
Content-Disposition: inline # browser will attempt to display it
Content-Disposition: attachment # browser will always download it
You can also specify the filename in both cases, should the user choose to download it:
Content-Disposition: inline; filename="table.xls"
Content-Disposition: attachment; filename="table.xls"
How to ensure that the Content-Disposition is specified to inline depends on where you're storing your files. If you're storing them on the filesystem, I think that the Rails::Static middleware already has the "inline" behaviour. If not, you can switch to download_endpoint.
If you're storing them on Amazon S3, you can specify the default :content_disposition upload option on Shrine::Storage::S3 initialization:
Shrine::Storage::S3.new(upload_options: {content_disposition: "inline"}, **options)

Related

Paperclip uploads for docx file is being downloaded as zip files?

I have checked the Mimetype of the docx file and it shows: 'application/octet-stream'
But checking it without any content in it shows application/vnd.openxmlformats-officedocument.wordprocessingml.document as mimetype.
I don't know whether the problem is with the content inside the file also,
while uploading the file with paperclip it shows:
#content_type="application/vnd.openxmlformats-officedocument.wordprocessingml.document", #headers="Content-Disposition: form-data;
But when we check the file content after the upload it shows as "application/zip".
Tried all the mimetypes, but it doesn't seams to work.
Meanwhile other docx files are uploaded and downloaded in fine way, this particular file alone been downloaded as zip file while downloading it form s3 bucket.
I cannot provide the file because it is confidential so please leave suggestions if you have any solution for this ?
Note: the same file when it is uploaded in google drive and downloaded or also downloaded in safari it is downloaded fine the problem occurs when downloading it in chrome browser.
Try adding this to your config/initializers/mime_types.rb
[['application/vnd.openxmlformats-officedocument.presentationml.presentation', [[0..2000, 'ppt/']]],
['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', [[0..2000, 'xl/']]],
['application/vnd.openxmlformats-officedocument.wordprocessingml.document', [[0..2000, 'word/']]]].each do |magic|
MimeMagic.add(magic[0], magic: magic[1])
end
Don't forget to restart the server after :)

How can I block file uploads in Rails?

I have a rails app (v4.2). I have two actions that permit an image upload using paperclip. I have paperclip validation on the mime types.
Anti-malware on the server found a bunch of PHP files in /tmp like this one:
/tmp/RackMultipart20190610-9668-u9nebk.php
I assume they are created in the file upload process.
Two questions:
How can I track down where they came from? Looking in my production.log, I see a bunch of 404s for posts to bogus joomla & wordpress .php paths but nothing that could have been responsible for these uploads.
How can I prevent them in the future?
I'm using rack attack and can block .php file extensions but how can I block file uploads in forms?
We have two places where signed in members can upload images or PDFs. How can I block all other attempts to upload files?
File uploading by-pass is a common technique for uploading webshell's and other stuff.
There are 2 basic methods that will help you to decrease the amount of file uploaded to your server:
MIME Content-type validation: If you validate the content-type of the uploaded file you (since you just want images) you can assure that only image-type files are uploaded:
:content_type => ["image/gif", "image/jpg", "image/jpeg", "image/png", "image/bmp", "image/x-bmp"]
But this still can be bypassed, so you need to add another verification:
File extension validation: You also should add a file extension validation to assure you only permit image-type extensions to your upload.
I've find a cool post where it shows a good implementation of file extension validation: https://stevenyue.com/blogs/validate-attachment-file-size-and-type-in-rails/
Make sure you implement both of these techniques and you should be fine.

How to name download file

I'm calling a web service to download a file, but it always assigns a generic name to the download. Every file I download has the same name.
So I appended "/filename.pdf?a=true" to the end of the URL as follows:
http://localhost/api/node/content/b52b3136-1cf0-48f2-a109-676a16015612/myfilename.pdf?a=true
Now on Firefox, the file downloads with the desired: myfilename.pdf.
But this isn't working on IE or Chrome.
What is wrong with this?
You want a header: Content-Disposition: attachment; filename=my_file_name.pdf
Will force a download (instead of an inline display) and set the file name. If you do not force a file name, but allow inline display (via PDF browser plugin) the filename is meaningless, which is, why it is often ignored by browsers.

Setting Content-Disposition to attachment using Ruby on Rails and Paperclip

I have a – hopefully small – problem.
I am using Ruby on Rails and Paperclip to handle file uploads.
Now I want to automatically set the Content-Disposition header to "attachment" so that when the user clicks a link, the file is downloaded instead of shown directly in the browser.
I found the following solution for Amazon S3:
Download file on click - Ruby on Rails
But I don't use S3.
Can anybody help?
Thanks in advance,
/Lasse
If you use File Storage, Paperclip stores the files within the RAILS_ROOT/public/system folder (configurable using the :path option).
Files from the /public folder are served directly as static files. "Rails/Rack never sees requests to your public folder" (to quote cwninja).
The files from the /public folder are served by the webserver running this app (for example Apache or WEBrick in development). And the webserver is responsible for setting the headers upon serving the file. So you should configure the webserver to set the correct headers for your attachment.
Another option is to build a controller or some Rack middleware to serve your paperclip attachments. There you can do something like response.headers['Content-Disposition'] = 'attachment'.
Third option is to use S3, then you can store headers (like Content-Disposition) within the S3-object. S3 then serves the paperclip attachment using those headers.
According to this link, you can do the following:
<Files *.xls> ForceType application/octet-stream Header set Content-Disposition attachment </Files>
<Files *.eps> ForceType application/octet-stream Header set Content-Disposition attachment </Files>

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.

Resources