TemplateHandler Changes from 2.1 to 2.2

I've been attempting to get prawnto (template wrapper around "prawn", a native ruby PDF generator) working under Rails 2.2.

Repo is here: http://github.com/thorny-sun/prawnto/tree/master

To start off, I set it up and it gives an "unknown method 'compile'" error.

Looking through the code, as well as Rails...

So, as far as I can tell between Rails 2.1 -> 2.2, TemplateHandlers have switched from outputting their template code in a "render" method, to outputting code to be compiled in a "compile" method. Prawnto as it stands now doesn't support the compile method, but I'd like to build that functionality in if possible. Question is: does anyone know of any resources for Rails 2.2, on someone's blog or otherwise, that speak to the changes made to TemplateHandler in Rails, and how to update a plugin from "rendering" to "compiling" to match?

Thanks for your time, Brady

Hey,

I just checked out your source and it looks like your already on the right track.

Right now you are handling the eval with "@view.instance_eval source, template.filename, 1". The compile method will actually handle this for you and make sure the same template doesn't need to be eval'd twice.

Instead of returning a string from render, return your "source" string and it will be taken care of for you.

Here is a good example to get you started.

http://gist.github.com/25022

Thanks Josh!

That's great, and should definitely get me on track to getting this working. I'm wondering though why Rails has moved to using compiled code? Is there really any performance benefit when the code being compiled is ruby code itself?

Regards, Brady

Yes, you source will get compiled into a ruby method and it will just run that instead. Its much faster.

Let me know if there are any other issues you run into. Just email me "josh at joshpeek dot com".

Hey Josh, Appologies for the late entry to this thread -- finally getting around to making prawnto template handler plugin work with 2.2. But in this thread you seem to contradict what I thought you had told me earlier in a github message:

josh said 3 months ago:

Your right! There is nothing to compile. However we do wrap the template with some ActionController helpers. We also need to convert it to a string so we can eval it later with the proper local assigns.

Hey Josh! I’m trying to better understand rails compiled templates, and I was hoping you might spare a minute to help. I understand the point of compiling ERB, for instance, cuz you can save time by not having to translate to ruby code everytime. BUT I don’t understand why you would want to make builder compiled? A builder template would already be ruby code, so is there another advantage here I’m missing? thanks for the help! you’ll be helping make prawnto even better :slight_smile:

-thorny_sun

so are you saying now that ruby source is somehow getting run faster since it is getting "compiled". I'm very confused. What if we take the builder template as an example (since prawnto template handler works very similarly in that it is just ruby code) -- is there any speed gain expected by "compiling" it? Or did I just misunderstand?

thanks for the help! -thorny_sun

In most cases, you going to have to compile it no matter what. In your prawnto template handler you directly call `@view.instance_eval source, template.filename, 1`. While this works, you are rebuilding and reevaling the template ever run. This is really slow. You could make this optimizations internally, but ActionView can take care of all this for you if you just return the source from the handler instead.

Josh,

ah ok-- I get it now -- thanks so much for helping me understand!

follow up question: I also have an option where the user can specify a template to be run as if it were inside a pdf.instance_eval where pdf is just the Prawn::Document object. This makes the template more compact, since the user avoids having to type "pdf." all the time. (i.e. "pdf = Prawn::Document.new; pdf.instance_eval template.source;") Soooo-- I'm assuming that having the "pdf.instance_eval" in the eval'd string kinda defeats the benefits of using compile? Could I get around this by mimicking the compile paradigm and creating a method and calling that method within the string to be eval'd?

thanks so much for the help! -thorny_sun

This should work:

"pdf = Prawn::Document.new; pdf.instance_eval do\n#{template.source}\nend"

This string will get eval'd into a method. Big difference between it actually running. AV will create something like this for you:

def _pdf_app_views_docs_show   pdf = Prawn::Document.new   pdf.instance_eval do     # the actual template source will be here     text "Hello, World"   end end

I get it-- perfect-- thanks!

another minor question: It seems you prefer to have the source surrounding the "template.source" be separated by semicolons rather than newlines? I see you've also gotten rid of the line count property. I assume that is to keep things simple and bug reported line numbers accurate? But what if there is an issue with the first line number-- wouldn't that come back with a lot of extra stuff (in my case the surrounding code is very long and would come back with a very uselessly long string) -- or am I missing something again?

-thorny_sun

Correct, the line offset thing is gone. So I'd recommend you wrap your block "pdf.instance_eval { ... }" so the line numbers are correct.

Hello,

I am wondering whether the template handler issue has been fixed for Rails 2.2.X Is there a work around?

Greetings and thanks for the great plugin.

Michael Kastner