Upload Wicked generated PDF to AWS S3 in Rails 5 - ruby-on-rails

I am generating invoices as PDFs and want to upload them directly to S3.
I am using Wicked-PDF and the official AWS SDK.
gem 'wicked_pdf'
gem 'aws-sdk-s3', '~> 1'
Now I create the PDF:
pdf = render_to_string pdf: "some_file_name", template: "invoices/download", encoding: "UTF-8"
And want to upload it:
s3 = Aws::S3::Resource.new(region: ENV['AWS_REGION'])
obj = s3.bucket('bucket-development').object('Filename')
obj.upload_file(pdf)
The error I get:
ArgumentError: string contains null byte
If I store the PDF first to a defined path and use the save_path it works:
save_path = Rails.root.join('public','filename.pdf')
File.open(save_path, 'wb') do |file|
file << pdf
end
But I would like to upload he temporary PDF directly to S3 without saving the PDF first to my public folder.

The upload_file method from AWS S3 SDK is working with files - see the method's description.
For uploading an object from memory, you should use the put method - see the method's description in the 2nd way of uploading on this page

Related

Can I upload a Prawn generated PDF to Cloudinary on Rails?

I am generating a PDF file using the Prawn gem and trying to upload the file to Cloudinary, but I'm getting the error below.
"#<NoMethodError: undefined method `match' for #<Prawn::Document:0x00007f80b51545e0>>"
The code in Rails that I am using is as follows. It generates a file in the root directory but giving the aforementioned error:
pdf = Prawn::Document.new
pdf.text "Hello World"
pdf.render_file "example.pdf"
result = Cloudinary::Uploader.upload(pdf, options = {})
I have been able to upload the same file manually to Cloudinary. Is this programmatically possible within Rails? I cannot find any resources online one way or the other.
Cloudinary is working in my project just fine for image files.
***** UPDATE *****
The upload worked with the following code. It creates a pdf file in a directory, uploads it to Cloudinary, then deletes it:
pdf = Prawn::Document.new
pdf.text "Hello World"
#creates file in directory
path = "public/system/temp_files/pdf_files/example.pdf"
pdf.render_file(path)
result = Cloudinary::Uploader.upload(path)
#deletes file in directory
File.delete(path)

Path to temporary Wicked PDF file in Rails 5

I am creating a PDF file using Wicked:
pdf = WickedPdf.new.pdf_from_string('<h1>Hello There!</h1>')
I assume that this creates a temporary file somewhere. How can I get the path to this temp file?
you can do this when you are creating the pdf only u can pass in the option of your desired temp path
pdf = WickedPdf.new.pdf_from_string('<h1>Hello There!</h1>', {temp_path: "your path here")
Refer this link for more inputs this contains the function that you are using and the inputs that can be passed
Please refer to example of https://github.com/mileszs/wicked_pdf#super-advanced-usage.
The official example use File
pdf = render_to_string pdf: "some_file_name", template: "templates/pdf", encoding: "UTF-8"
# then save to a file
save_path = Rails.root.join('pdfs','filename.pdf')
File.open(save_path, 'wb') do |file|
file << pdf
end
You may use tempfile to do it as
pdf_string = WickedPdf.new.pdf_from_string(...)
overlay = Tempfile.new('overlay')
overlay.binmode
overlay.write(pdf_string)
overlay.close
overlay.path # to get path
Checking the source of WickedPDF it has a TempFile
The temporary file should be created in the temporary directory as defined in options, or in Dir.tmpdir.

combine_pdf not combining the pdfs

I think I am missing something simple. Using combine_pdf: I am attempting to combine two pdf files into one pdf, and then send that resulting pdf with send_data in my rails app.
Here is my code in a controller:
pdf = CombinePDF.new
# returns an array, each element is a string of an absolute path
# to the file I want to upload
absolute_upload_paths = #obj.attachments.collect {|obj| obj.my_attachment.path}
absolute_upload_paths.each {|upload_path| pdf << CombinePDF.load(upload_path)}
send_data pdf, filename: “my_combined_pdf”, type: "application/pdf"
What results is that a damaged pdf file gets sent which cannot be opened:
Adobe Acrobat Reader could not open 'VR_Voc_Eval-51.pdf' because it is either not a supported file type or because the file has been damaged (for example, it was sent as an email attachment and wasn't correctly decoded).
What am I missing? How can I use this gem to combine two existing pdf files into one pdf and then send it to the user?
It looks like the README for that library calls .to_pdf when sending the data. Hopefully calling #to_pdf on the pdf object like in the example will fix your issue.
send_data pdf.to_pdf, filename: “my_combined_pdf”, type: "application/pdf"
https://github.com/boazsegev/combine_pdf#rendering-pdf-data

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

How to use docx gem with amazon s3?

I have this create action to extract data from doc and docx files using the docx gem and the msworddoc-extractor gem
if #subject.save
if #subject.odoc.present?
#odoc_url = #subject.odoc.url
if File.extname(URI.parse(#odoc_url).path) == ".docx"
#subject.homework= ""
doc = Docx::Document.open(#odoc_url)
doc.paragraphs.each do |p|
#subject.homework = #subject.homework+p.to_html
end
else
MSWordDoc::Extractor.load(#odoc_url) do |doc|
#subject.homework= doc.whole_contents
end
end
#subject.save
end
now, doc files works fine.. My problem is with doc = Docx::Document.open(#odoc_url) when i use the code on my local machine it works fine.. when i push into production i get an error Zip::Error: File s3.amazonaws.com/~~~ not found I'm not really sure how to load the file to be accessible to the docx gem
So i finally got it without having to download the file using open-uri
doc = Docx::Document.open(open(#odoc_url).path)

Resources