I am inside a Rails controller and I am trying to access my instance variable in a block:
This gives an error saying that "no method field1 for Nil":
Prawn::Document.generate("hello.pdf") do
@model.field1
end
However, if I do this, then it works:
my_model = @model
Prawn::Document.generate("hello.pdf") do
my_model.field1
end
Could this have something to do with ActiveRecord accessors or instance variables in a block?
That's happening because code inside block is executed in context of Prawn::Document object. Let's go inside this code:
module Prawn
class Document
def self.generate(filename,options={},&block)
pdf = new(options,&block)
pdf.render_file(filename)
end
def initialize(options={},&block)
if block
block.arity < 1 ? instance_eval(&block) : block[self]
end
end
end
end
As you can see, block
is executed with Document
object as self
. It try to find @model as instance variable of self
, can't do this and return nil
. If you use local variable model
, you get help of closures and your code is working properly
This kind of problem appears when a block is being executed in a different context, usually through a instance_eval
. So let's check the code:
#lib/prawn/document.rb: Document#initialize
if block
block.arity < 1 ? instance_eval(&block) : block[self]
end
There you have your instance_eval
, and you can also see the solution: pass a block that accepts the document as argument and you'll now be able to access the instance variables as usual:
Prawn::Document.generate("hello.pdf") do |doc|
@my_model.field1
end