ruby-on-railsprawnprawnto

Prawnto and Prawn: Reusing cells created with pdf.make_cell()


I've successfully implemented Prawnto_2 with Prawn in my Rails 4 application. However, I ran across some strange behavior with table cells that I could not find an answer to.

In my implementation, my application can create a multi-page PDF containing a large table on each page. Each table has the same design and contains similar data, and thus, has identical table headings.

To speed things up and stay DRY, I would create a header row with:

header = []
(0..6).each do |index|
    header << pdf.make_cell(:content => "Heading #{index}", :width => 140, :borders => [])]
end

Then, with multiple calls to pdf.table(), I could re-use that header row for each table on which I wanted the header row to appear:

4.times do |i|
    pdf.table([header] + more_rows)
    # the more_rows variable is an array containing additional rows to be shows beneath the header
end

With the loop above, I would expect to have four tables, each having the same top row. This is true, however, the table dimensions are goofed. Namely, the column widths are ignored in subsequent tables and the table width is not respected. The first table is perfect, but the second and beyond succumb to this problem.

The only way I was able to solve this was to create the header row each time I created a table, which means lots of code duplication. It works great, but isn't DRY at all.

So, in the example above, why would reusing header cause varying column and table widths? Is there a more proper way to reuse a Prawn::Table::Cell object?


Solution

  • My suspicion here is that reusing the Cell object is a bad idea. It's probably not an immutable object and modifies itself during the render based on what's going on. Looking at the implementations of the Cell class, they have an internal attribute @pdf that they perform operations on, move, and a few others. So, by reusing these in different areas of the document, you're going to get odd results as the thing is move'd more times than it should be.

    Throw your header logic into a function, so that new cells are created for each call to it, and you can still keep your code looking reasonably clean .