PDF file generated by Prawn throws "Failed - server error" when I try to download it from the browser's pdf viewer - ruby-on-rails

I have a PDF file that is generated in ruby on rails with Prawn.
I used send_file with disposition: inline.
pdf = <A method is called to generate the PDF>
pdf.render_file file_path # file_path = public/assets/reports/test_report.pdf
send_file(file_path, filename: 'test_report.pdf', type: 'application/pdf', disposition: 'inline')
The pdf is displayed as expected but when I try to download it from the browser's pdf viewer after the pdf is displayed, it throws me an error saying "failed - server error".
Download button
error
Has anyone faced this issue or have a possible solution to it?
Tried using send_data instead of send_file the issue still remains. I have tried searching through the internet including stack overflow, didn't find a proper solution. I went through PrawnRails documentation, no luck there too.

Related

How to handle when API returns PDF binary stream

I have an e-signature tool I'm using and when I want to download the executed file, it's a simple GET request. The issue is that it:
Returns PDF file binary stream of the document which you can save as PDF file.
When examining the file it looks something like this (this is only a snippet):
> r.body
=> "%PDF-1.4\n%\xE2\xE3\xCF\xD3\n77 0 obj\n<</ByteRange [0 141 16527 447870 ] /ContactInfo()/Contents <30820ffe06092a864886f70d010702a0820fef30820feb020101310f300d06096086480165030402010500300b06092a864886f70d010701a0820e393082042a30820312a00302010202043863def8300d06092a864886f70d01010505003081b431143012060355040a130b456e74727573742e6e65743140303e060355040b14377777772e656e74727573742e6e65742f4350535f3230343820696e636f72702e206279207265662e20286c696d697473206c6961622e2931253023060355040b131c286329203139393920456e74727573742e6e6574204c696d69746564313330310603550403132a456e74727573742e6e6574204365727469666963
What can I do with this data to present it on the screen as a PDF?
You can use send_data, this will download the file or open it in the browser depending on which browser your user is using:
send_data(r.body, type: 'application/pdf', disposition: 'attachment', filename: 'file.pdf')
See further: https://apidock.com/rails/ActionController/Streaming/send_data

How to read a pdf response from Rails app and save to file with parallel tests?

Ok - I have the following in my test/test_helper.rb:
def read_pdf_from_response(response)
file = Tempfile.new
file.write response.body.force_encoding('UTF-8')
begin
reader = PDF::Reader.new(file)
reader.pages.map(&:text).join.squeeze("\n")
ensure
file.close
file.unlink
end
end
I use it like this in an integration test:
get project_path(project, format: 'pdf')
read_response_from_pdf(#response).tap do |pdf|
assert_match(/whatever/, pdf)
end
This works fine as long as I run a test singly or when running all tests with only one worker, e.g. PARALLEL_WORKERS=1. But tests that use this method will fail intermittently when I run my suite with more than 1 parallel worker. My laptop has 8 cores, so that's normally what it's running with.
Here's the error:
PDF::Reader::MalformedPDFError: PDF malformed, expected 5 but found 96 instead
or sometimes: PDF::Reader::MalformedPDFError: PDF file is empty
The PDF reader is https://github.com/yob/pdf-reader which hasn't given any problems.
The controller that sends the PDF returns like so:
send_file out_file,
filename: "#{#project.name}.pdf",
type: 'application/pdf',
disposition: (params[:download] ? 'attachment' : 'inline')
I can't see why this isn't working. No files should ever have the same name at the same time, since I'm using Tempfile, right? How can I make all this run with parallel tests?
While I cannot confirm why this is happening the issue may be that:
You are forcing the encoding to "UTF-8" but PDF documents are binary files so this conversion could be damaging the PDF.
Some of the responses you are receiving are truly empty or malformed.
Maybe try this instead:
def read_pdf_from_response(response)
doc = StringIO.new(response.body.to_s)
begin
PDF::Reader.new(doc)
.pages
.map(&:text)
.join
.squeeze("\n")
rescue PDF::Reader::MalformedPDFError => e
# handle issues with the pdf itself
end
end
This will avoid the file system altogether while still using a compatible IO object and will make sure that the response is read as binary to avoid any conversion conflicts.

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

Rails send_data passes plain text path as file

I cant figure out what Im doing wrong here. Im using Carrierwave to allow users to upload PDF files to AWS. So far upload and record creation go off without a hitch and when browsing the S3 bucket Im able to download and read the file no problem.
The issue Im having is with the "send_data" function in my controller The file download is being triggered, but instead of the PDF thats in AWS im getting a txt file(with PDF extension), that contains only the path to the file.
here is my code, hopefully more experienced eyes will spot my error.
send_data #document.file.url.to_s, :type => "application/pdf", :disposition => "attachment", :filename => #document.title.to_s
Look at semantic for those methods:
send_data(data, options = {})
send_file(path, options = {})
For send_data() you should open and read the file, for send_file() you can use just a path to file.
send_data(File.read(#document.file.url.to_s), type: "application/pdf", disposition: "attachment", filename: #document.title.to_s)

Sending zipped files as attachments

I have a rails application that creates a couple of csv file, zips them up and sends them to the client as an attachment(for download) using this line:
send_file t.path, :x_sendfile => true, :type => 'application/zip', :filename => "invited_friends_stats.zip"
When I view the zipped file created on the server, I'm able to use it, however, when I download the file through the application, it uncompresses into a .zip.cpgz file, while in turn compresses into a zip file which compresses into a .zip.cpgz file, etc, etc.
I then downloaded "The Unarchiver" app (on Mac OSX) and when I try and open the .zip file I get an error: "the contents cannot be extracted with this program"
Does anyone have any idea why this is happening? Encoding error, etc? Is there something I'm missing from the line above, or in my configuration that would fix this?
You try to stream the ZIP file. Try adding :disposition => 'attachment' to force the browser to download the complete file.
Try setting the Content-Disposition response header with something like this
response.headers['Content-Disposition'] = "attachment; filename=\"#{#filename}\""

Resources