Writing to .zip file from binary data - ruby-on-rails

I am trying to write a rails test (Using Capybara & Poltergeist) to test .zip file download functionality.
I have the binary data of a .zip file being returned from an XHR request and I am hoping to write this data into a .zip file locally and carry out further tests from there.
The following method emulates a click on a button which, when in-app, returns a zip file of all the files that have been selected:
# Perform XHR
def download_file(link)
page.execute_script("window.downloadFile = function(){ var url = window.location.protocol + '//' + window.location.host + '#{link}'; return getFile(url); }")
page.execute_script("window.getFile = function(url){ var xhr = new XMLHttpRequest(); xhr.open('GET', url, false); xhr.responseType = 'blob'; xhr.send(); return xhr.response; }")
begin
file = page.evaluate_script('downloadFile()')
rescue
raise "Error during XHR. Is url valid?"
end
file
end
I am trying to write the response to file here:
file = download_file(url)
file_path = "#{Rails.root}/tmp/files/download.zip"
File.open(file_path, 'wb'){ |f| f.write file }
When trying to unzip the resulting file using unzip tmp/files/download.zip I'm given the following response:
Archive: tmp/files/download.zip
caution: zipfile comment truncated
error [tmp/files/download.zip]: missing 3182550208 bytes in zipfile
(attempting to process anyway)
error [tmp/files/download.zip]: start of central directory not found;
zipfile corrupt.
(please check that you have transferred or created the zipfile in the
appropriate BINARY mode and that you have compiled UnZip properly)
I have tried overriding the MIME type to text/plain, application/zip etc. but to no avail.
Any suggestions?

I extended the Tempfile class to include a write binary function
class Tempfile
def openBinary
#tmpfile.close if #tmpfile
#tmpfile = File.open(#tmpname, 'wb')
#data[1] = #tmpfile
__setobj__(#tmpfile)
end
end
This made it possible for my system to parse zip files and then read the using Zip::ZipFile class.

Related

When I download Excel files, strange files are stored

I want to download uploaded files such as .zip, .xlsm, xlsx, pdf... ..., etc., that have been uploaded, I want to eventually compress them into a zip file for download.
However, if the uploaded files are not zipped, they will be downloaded with strange files stored in them.
In this case, .xlsm
Source Code
class DownloadZipsController < ::ApplicationController
def index
file_name = "#{Time.current.strftime("%Y%m%d_%H%M%S")}.zip"
zip_file = Tempfile.new(file_name)
Zip.unicode_names = true
Zip::OutputStream.open(zip_file.path) do |zip|
params[:product_ids].each do |product_id|
product = Product.find(product_id)
zip.put_next_entry("output.zip")
zip.print Net::HTTP.get URI.parse(product.submit_zip_file.url)
end
end
send_file zip_file.path,
type: "application/zip",
disposition: "attachment",
filename: file_name
zip_file.close
rescue => e
logger.debug e.backtrace
redirect_to request.referer, alert: e.message
end
end
Uploaded files are stored in AWS S3.
Is there any solution to this problem?
Office Documents such as .xlsm, .xlsx, .docx, and others are in fact zip files containing the document as a xml file plus additional resources.
The file tree you have shown in your screenshot shows the content of one such document if you interpret it as a zip file and unpack.
It appears that somewhere in your code, you have detected the document file as a zip file and interpreted it as such which resulted in its contents to be unpacked.
This is not apparent from the code you have posted though, so I would assume that you have some additional handling of zip files somewhere else (such as a function to download existing files which may then be send with a wrong content type to the browser, i.e as an application/zip rather than application/vnd.ms-excel.sheet.macroEnabled.12).

How to send the zip file in Rails via Grape API

I have a set of files that are present in s3 and I have to zip them all and send the zipped file to the front end(ReactJS).
I am successfully able to create a folder in the tmp of the project and also zip them. Unfortunately, I get the error when I try to expand saying Unable to expand
Here is the code -
data = Zip::File.open(zip_file_name, ::Zip::File::CREATE) do |zipfile|
files.each do |file|
zipfile.add(file, file_path)
end
end
content_type "application/octet-stream"
header['Content-Disposition'] = "attachment; filename=abcd.zip"
env['api.format'] = :binary
File.open(zip_file_name, 'rb').read
Is there a way to solve the problem? Thanks

Testing File Creation in Rails

My App saves Files to the Filesystem via an base64 encoded API. Here is my (simplified) controller:
def create
file = "name.pdf"
folder = "downloads"
FileUtils::mkdir_p folder
f = File.open File.join(folder, file), "wb"
if f.write Base64.decode64(params[:file])
f.close
end
Now I want to test for an actual file creation. How do I check whether there is a file or not?
Thanks for your input!

Serving excel sheet (.xls) to browser for download using rails & angular

I am using spreadsheet gem to generate .xls file. After writing it to a file, I am trying to send to client browser for download.
Below is the code in rails
workbook = Spreadsheet::Workbook.new
# Constructed the data
file = "/path/to/file/sheet.xls"
workbook.write file
send_file file
This file when opened contains expected data in ideal format.
Below is the code in js:
CustomRestService.custom_post("report",{report_data: angular.toJson($scope.report_data)},"download_xls",{}).then (data)->
if data
hiddenElement = document.createElement('a')
angular.element(document.body).append(hiddenElement)
hiddenElement.href = 'data:attachment/xls,' + encodeURI(data)
hiddenElement.target = '_blank'
hiddenElement.download = "report.xls"
hiddenElement.click()
hiddenElement.remove()
But the file getting downloaded in browser contains junk data. I tried multiple solutions like below:
Using send_data, instead of send_file
Generated xls data and wrote to StringIO object to directly download
Constructed Blob object in js, with type as "application/vnd.ms-excel" and trying to download it.
All attempts failed, as I am missing something. All suggestions are welcome.
filename = "/path/to/file/sheet.xls"
tempfile = Tempfile.new(filename)
workbook = Spreadsheet::Workbook.new
...
workbook.write(tempfile.path)
send_file tempfile.path, :filename => filename

Django Custom File Storage - write contents to file

I'm trying to write a custom django backend that writes the contents of an uploaded file to an output file while also saving the file as it normally would. I assumed I could do this by overriding the _open function of Django, but no luck. Anyone know how to accomplish this? Here's what I've been messing around with
from django.core.files.storage import FileSystemStorage
class TestStore(FileSystemStorage):
def _open(self, name, mode='rb'):
data = open(name, 'rb')
dataRead = data.read()
filename = '/home/somewhere/testdir/output.txt'
FILE = open(filename, 'w')
FILE.write(dataRead)
FILE.close()
data.close()
return name
If you already created the file you can just output it with content-disposition:
response = HttpResponse(data, content_type='text/txt')
response['Content-Disposition'] = 'attachment; filename=filename'

Resources