0

I have a Rails app, in which I need to render one of the views as a downloadable PDF. The view itself is composed of many partials, which in turn are composed of more partials and so on. This is the top-level view:

<meta charset="utf-8" />
<%= javascript_include_tag "jquery-ui.min", media: "all", "data-turbolinks-track" => true %>
<%= javascript_include_tag "report", media: "all", "data-turbolinks-track" => true %>
<%= stylesheet_link_tag "report_style", media: "all", "data-turbolinks-track" => true %>
<div class="report">
    <%= render partial: "details", locals: { examinee: @examinee, te: @test_event } %>
    <div class="page-break"></div>
    <%= render partial: "grades", locals: { scores: @test_event.scores, tasks: Task.tasks_for_report(@test_event.language) } %>
    <div class="page-break"></div>
    <%= render partial: "ld", locals: { test_event: @test_event } %>
    <%= render partial: "review", locals: { test_event: @test_event } %>
    <div class="page-break"></div>
    <%= render partial: "appendix" %>
</div>

Due to the complexity of the rendered view, I prefer generating a PDF from html over writing everything twice, once as .html.erb and again as pdf.erb.

I have tried both pdfkit and wickedpdf, but in both cases I have failed:

pdfkit gets my Thin server hanged, no matter what I tried - None of the solutions suggested here, here and here had any impact, things still suck.

wicked_pdf has actually managed to generate a PDF, but then again it ignored all of my css and js code, even when called with wicked_pdf_javascript_include_tag and its corresponding css twin. This can't go as I need my page breaks and all of the content created by the various js scripts (for example, some plots which are made by chartist).

Any Ideas?

Spätzle
  • 709
  • 10
  • 20

1 Answers1

0

If you are running Rails with a single-threaded webserver (like webrick), and your PDF generation process involves getting data from another endpoint in your app (like AJAX in your JavaScript), it is going to hang in a deadlock, because the request for the asset to build your PDF is queued behind the actual building of the PDF.

It should work just fine in production because most production environments are setup to run multiple web workers (with passenger or unicorn or something), but to properly test this in development mode, you'll need to configure your app to run multiple web workers, so your Ajax request can happen in another thread and return back to your main request.

I would suggest you add the puma gem to your Gemfile, and run your dev server with rails server Puma --workers 3 (by the way, puma is included by default in new Rails 5 apps because people were having this same issue with ActionCable requests).

wicked_pdf_javascript_include_tag is provided to read from disk for extra speed in building your PDF, and does have some issues with a few libraries, and depending on your config, may require your JS and CSS to be named in the config.assets.precompile list.

Unixmonkey
  • 18,485
  • 7
  • 55
  • 78
  • As I've written above, I am working with Thin, which supports multi-threading. – Spätzle Jul 20 '17 at 07:01
  • @Spätzle But are you running it with multiple threads? By default it is still serves a single request at a time. `thin start --servers 3` should start 3 threads. – Unixmonkey Jul 20 '17 at 14:22