prawn
prawn copied to clipboard
Rescue after Exception leaves the document in an invalid state
In a project of mine I allow my users to create a template that will be used to generate PDFs using Prawn.
A template has one or more 'blocks' that are evaluated sequentially while writing the PDF. There are different kind of blocks I allow my users to create, such as simple text, floating boxes, images and tables.
blocks.each do |block|
begin
case block.type_id
when TemplateBlock::TYPE_TEXT
render_block_text(block)
when TemplateBlock::TYPE_SPACE
render_block_space(block)
when TemplateBlock::TYPE_BLOCK
render_block_block(block)
when TemplateBlock::TYPE_LOGO
render_block_logo(block)
when TemplateBlock::TYPE_TABLE
render_block_table(block)
end
rescue
end
end
Since I cannot validate 100% what the users enters without restricting freedom, it sometimes happens that a specific block cannot be rendered correctly. For example, I had a user who wanted to render a logo block (image) repeated on every page, which was larger than the page itself. This resulted in a PDF::Core::Errors::EmptyGraphicStateStack
exception which was correctly caught (and silently ignored) by the rescue block listed in the sample above.
However, I expected the rest of the blocks after the failed one to render correctly, but this was not the case. All blocks after the one who failed were simply not displayed on the final render. Is this a bug, or am I doing something wrong?
Inside render_block_logo
the Prawn method image
is called as follows. This is also the line where the exception occurs on:
repeat :all do
image block.payload.path, opts
end
To reiterate, this works fine when all attributes are within reasonable limits. I want to simply fail silently and skip blocks where 'unrenderable' demands are made by my users.
Still running into this problem from time to time. Also happens when a bounding box has insufficient size for the content. However, I can't seem to figure out why my exception handling block will not pick it up. Even when I specifically catch the PDF::Core::Errors::EmptyGraphicStateStack
exception
@cdekker Could you please provide a minimal example that reproduces the issue?
The exception not being handled was an error on my part. It occured in a part that was outside of my block. However, I reproduced the other issue where a CORRECTLY caught exception causes the rest of the document to not be rendered.
Quick example of 3 blocks:
- first is fine
- second gives exception
- third is fine but doesn't get rendered after caught exception
def test
doc = Prawn::Document.new(:page_size => 'A4', :page_layout => :portrait)
begin
# Text wont fit. Pushed to next page
doc.bounding_box [50, 50], :width => 50, :height => 50 do
doc.text 'Looooooooooooooooooooooooooong text' * 10
end
rescue
end
begin
# Text wont fit. Repeat every page. EXCEPTION!
doc.repeat :all do
doc.bounding_box [200, 50], :width => 50, :height => 50 do
doc.text 'Looooooooooooooooooooooooooong text' * 10
end
end
rescue
end
begin
# Standard fitting text in box, repeated
# WILL NOT BE RENDERED BECAUSE OF PREVIOUS (CAUGHT) EXCEPTION
doc.repeat :all do
doc.bounding_box [350, 50], :width => 50, :height => 50 do
doc.text 'fitting!'
end
end
rescue
end
send_data doc.render, type: :pdf, disposition: 'inline'
end
@cdekker Thank you. We will look into it a bit later.