Pergunta

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?

Foi útil?

Solução

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

Outras dicas

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
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top