Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Certain PDFs as Template: NoMethodError (undefined method `[]' for nil:NilClass) #386

Closed
jaybrueder opened this Issue · 5 comments

6 participants

@jaybrueder

Hi!

I'm encountering a

NoMethodError (undefined method `[]' for nil:NilClass)

Exception with certain PDFs that I want to use as a template.

Another problem is, that a begin...rescue wont rescue the exception.
It still crashes the app:

begin
    start_new_page(:template => "#{Rails.root}/public#{upload.document.url}")
rescue
    start_new_page
end

I'm using the Master-Branch of the gem.

gem 'prawn', :git => "git://github.com/prawnpdf/prawn.git", :branch => "master"

Does anyone know what causes this error with some PDFs or at least why it won't be rescued?

@bradediger
Collaborator

Can you provide either a PDF that triggers the error, or a stacktrace of the error itself? Otherwise we're just guessing as to what happened.

As for why the rescue doesn't seem to work, my guess is that by the time you hit the NameError, the damage is already done and you can't necessarily just keep on using the document.

@jaybrueder

I have put an example pdf here: http://juergenbrueder.com/pdfs/vorschau.pdf

The stack trace when rendering a PDF with the above PDF as template is included below.
It is not very informative. All I can say is that base_recipe_export.rb:124 is where the

start_new_page(:template => "#{Rails.root}/public#{upload.document.url}")

is located.

NoMethodError (undefined method []' for nil:NilClass):
app/pdfs/base_recipe_export.rb:124:in
rescue in block in recipe_pdf'
app/pdfs/base_recipe_export.rb:120:in block in recipe_pdf'
app/pdfs/base_recipe_export.rb:117:in
each'
app/pdfs/base_recipe_export.rb:117:in recipe_pdf'
app/pdfs/base_recipe_export.rb:66:in
block (2 levels) in render_recipes'
app/pdfs/base_recipe_export.rb:64:in block in render_recipes'
app/pdfs/base_recipe_export.rb:56:in
each'
app/pdfs/base_recipe_export.rb:56:in render_recipes'
app/pdfs/base_recipe_export.rb:50:in
render_all_others'
app/pdfs/recipes_export_pdf.rb:22:in initialize'
app/controllers/recipes_controller.rb:32:in
new'
app/controllers/recipes_controller.rb:32:in block (2 levels) in pdf_export'
app/controllers/recipes_controller.rb:30:in
pdf_export'
config/initializers/quiet_assets.rb:7:in `call_with_quiet_assets'

@TylerRick

It looks like your backtrace is only showing frames from your application files and therefore omits any lines from gem/framework source code. Those omitted lines would be needed to debug this.

If the error message shows up in your browser, there should be 3 links "Application Trace | Framework Trace | Full Trace" and you can see the full trace by clicking Full Trace.

If the backtrace is only showing in your log file, you might try adding this line to config/initializers/backtrace_silencers.rb:

Rails.backtrace_cleaner.remove_silencers!
@yob
Collaborator
yob commented

I've confirmed this is a bug, here's the stack trace using the provided template PDF

⚡ ruby -Ilib manual/templates/full_template.rb
    /home/jh/git/prawn-rw/lib/prawn/core/page.rb:38:in `layout': undefined method `[]' for nil:NilClass (NoMethodError)
    from /home/jh/git/prawn-rw/lib/prawn/document.rb:253:in `start_new_page'
    from manual/templates/full_template.rb:19:in `block in <main>'
    from /home/jh/git/prawn-rw/lib/prawn/document.rb:215:in `instance_eval'
    from /home/jh/git/prawn-rw/lib/prawn/document.rb:215:in `initialize'
    from /home/jh/git/prawn-rw/lib/prawn/document.rb:122:in `new'
    from /home/jh/git/prawn-rw/lib/prawn/document.rb:122:in `generate'
    from manual/templates/full_template.rb:16:in `<main>'

The template PDF defines it's MediaBox in the /Pages tree above the /Page, not on the /Page itself. it's perfectly legal for the PDF to do that, so we need to account for it.

I have an idea that should help and will hopefully be able to look at it soon.

@krishicks

I've run into this bug as well. The following tests expose the bug:

Modify the existing test for a PDF without a MediaBox entry (spec/template_spec.rb:164) such that it starts a new page after creating the Document:

it "should correctly import a template file that is missing a MediaBox entry" do
  filename = "#{Prawn::DATADIR}/pdfs/page_without_mediabox.pdf"

  @pdf = Prawn::Document.new(:template => filename)
  @pdf.start_new_page
  str = @pdf.render
  str[0,4].should == "%PDF"
end

This will cause the error that the bug was opened under.

Similarly, create a new document without a MediaBox-less template, but pass the template to start_new_page:

it "should work when the template is missing a MediaBox entry" do
  filename = "#{Prawn::DATADIR}/pdfs/page_without_mediabox.pdf"

  @pdf = Prawn::Document.new skip_page_creation: true
  lambda {
    @pdf.start_new_page(template: filename)
  }.should_not raise_error
end

I've looked into this a bit but don't have a good enough understanding of the structure of PDFs to make a good solution.

Adding a breakpoint at lib/prawn/core/page.rb:91 shows the following:

p @dictionary
=> 4
p document.state.store[4].data.keys
=> [:Type, :Parent, :Resources, :Contents]

Page#layout calls #dictionary expecting an object with data that has :MediaBox as a key, but the result from #dictionary has no such key at that index.

However, that key can be found at a different index, if we dig into :Pages:

p document.state.store[2].data[:Pages].data.keys
[:Type, :Kids, :Count, :MediaBox]

The fix made in 41b56e8 by James Healy seems to do a similar kind of lookup through the parents to find the :MediaBox key, but still fails in the case of the PDF being used as a start_new_page template.

Edited to add pull request: #468

@practicingruby practicingruby removed the stale label
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.