Serving PDF file using Ruby on Rails – blank/white pages in the downloaded file

For the brevity of this question let’s assume that I have a properly generated PDF file stored in memory and encoded in Base64 (generated outside of Ruby), such as this one:

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dW50IDE+PgplbmRvYmoKCjE0IDAgb2JqCjw8L1R5cGUvQ2F0YWxvZy9QYWdlcyA2IDAgUgovT3BlbkFjdGlvblsxIDAgUiAvWFlaIG51bGwgbnVsbCAwXQovTGFuZyhlbi1VUykKPj4KZW5kb2JqCgoxNSAwIG9iago8PC9BdXRob3I8RkVGRjAwNkQwMDYxMDA3MjAwNjMwMDZDMDAyMD4KL0NyZWF0b3I8RkVGRjAwNTcwMDcyMDA2OTAwNzQwMDY1MDA3Mj4KL1Byb2R1Y2VyPEZFRkYwMDRDMDA2OTAwNjIwMDcyMDA2NTAwNEYwMDY2MDA2NjAwNjkwMDYzMDA2NTAwMjAwMDM0MDAyRTAwMzI+Ci9DcmVhdGlvbkRhdGUoRDoyMDE1MDUxOTE2MzMxOCswMicwMCcpPj4KZW5kb2JqCgp4cmVmCjAgMTYKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDA1MTc0IDAwMDAwIG4gCjAwMDAwMDAwMTkgMDAwMDAgbiAKMDAwMDAwMDIwOCAwMDAwMCBuIAowMDAwMDAwMjI4IDAwMDAwIG4gCjAwMDAwMDA0MDcgMDAwMDAgbiAKMDAwMDAwNTMxNyAwMDAwMCBuIAowMDAwMDAwNDQ3IDAwMDAwIG4gCjAwMDAwMDQzMjIgMDAwMDAgbiAKMDAwMDAwNDM0MyAwMDAwMCBuIAowMDAwMDA0NTM4IDAwMDAwIG4gCjAwMDAwMDQ4NDMgMDAwMDAgbiAKMDAwMDAwNTAxNiAwMDAwMCBuIAowMDAwMDA1MDQ5IDAwMDAwIG4gCjAwMDAwMDU0MTYgMDAwMDAgbiAKMDAwMDAwNTUxMyAwMDAwMCBuIAp0cmFpbGVyCjw8L1NpemUgMTYvUm9vdCAxNCAwIFIKL0luZm8gMTUgMCBSCi9JRCBbIDxGQkE3OEI5RkI5QzcwRDVBMzlGOENDNkJBMjk3MTgyRj4KPEZCQTc4QjlGQjlDNzBENUEzOUY4Q0M2QkEyOTcxODJGPiBdCi9Eb2NDaGVja3N1bSAvREJEN0U3QTI2RDYxMTQ1NDVBODdGRjNGQ0FEQjQzRDgKPj4Kc3RhcnR4cmVmCjU3MjYKJSVFT0YK

My initial attempts (slightly refactored after a bit of googling around) looked like this:

send_data Base64.decode64(pdf).force_encoding(Encoding::BINARY), filename: "download.pdf", type: "application/pdf", disposition: "inline"

While the same code works for other file types (CSV, Excel spreadsheets) it’s binary PDF files that seem to draw a blank (pun intended). Oddly enough when I have a PDF file with several pages, the right amount of pages is included in the file but they’re all blank.

I’ve also tried serving a PDF from the disk (I generated the PDF using LibreOffice):

send_file "/path/to/file.pdf", :filename => "download.pdf", :type => "application/pdf"

But the result is the same. I’m running out of ideas, so I’d be grateful for any tips.

Note: I am not generating the PDF files using Ruby/RoR, so suggestions such as using Prawn are out of place. The files themselves are generated independently and stored as base64. I know for a fact that there isn’t a problem with the generation process as the base-encoded PDF I’ve included above is valid (I’ve checked it using online decoders and using other programming languages).


Source: ruby

Leave a Reply