Fork me on GitHub

Padrino and Template Inheritance

This post has been updated at 16/05/2013.

Rango was the first framework supporting template inheritance in Ruby. Now thanks to the template-inheritance gem and its new Padrino adapter you can have all the inheritance goodies in Padrino!

What Is Template Inheritance All About?

Template inheritance is trying to solve the very same problem as layouts: it's trying to keep developers' suicide rate low by not forcing them to repeat all the doctype html bullshit everywhere. However unlike layouts, template inheritance is more natural and mainly way more flexible (think about layout in another layout, using super calls just like in Ruby, mixins and all this crazy OOP shite). Django has very nice documentation about template inheritance, check it!

Of course, you can argue that you can hack this and that and after all content_for can help a lot ... that's true, but what really matters is the way how you think about templates. With template inheritance, suddenly templates aren't just chunks of HTML strings, but flexible ecosystem you can work with.

When Merb was killed by Engine Yard and the community was left without any usable framework I decided to write framework Rango, the first Ruby framework with template inheritance. After a while I extracted template-inheritance as a standalone gem and re-used it for example in static site generator Ace.

Recently I started to play around with Padrino framework, so I decided to write Padrino adapter for template-inheritance (kudos to pepe for great help!), so more people can use this wonderful technique.

Great! So How Can I Use It?

The setup is really dead simple. First, we have to register TemplateInheritance::Rendering to be used instead of the default rendering mixin. You can do so in app/app.rb:

require "template-inheritance/adapters/padrino"

class Microblog < Padrino::Application
  register TemplateInheritance::Rendering
end

Now let's define a basic action rendering a template (app/controllers.rb):

get "/" do
  @user = ENV["USER"]
  render "index"
end

And write the template (app/views/index.haml):

- extends "base"

- block(:content) do
  %h1== Hey #{@user}!

In this case with one template it'd be enough to just put all the HTML into app/views/index.haml, but it's not usually the case, so let's add at least one base template (app/views/base.haml):

!!! 5
%html
  %head
  %body= block(:content)

It's pretty straightforward, in app/views/index.haml we defined block content and in app/views/base.haml we put it to the proper place in the template.

You can clone this from GitHub, it's called padrino-template-inheritance-microblog. So far there is only this primitive example, but I want to expand it later on to show the full power of template inheritance.

Implementation Notes

The render we call in controllers is actually the original Padrino::Rendering::InstanceMethods#render which we don't patch in any way. Instead once the TemplateInheritance::Rendering is registered, it includes itself into the controller and then it register the original Padrino::Rendering, so it rewrites TemplateInheritance::Rendering#render but once it calls super, it won't invoke Sinatra::Application#render, but TemplateInheritance::Rendering#render. Crafty, right :) ?

It's not very important, although if you find a bug, it might not be bug of template-inheritance. During the work on this adapter we found Padrino bug #534, which Padrino guys immediately fixed (kudos for that guys!).

I'm going to write more about template inheritance and its advantages, because it seems like the Ruby community still isn't very familiar with this great concept. Sooo stay tuned and give it a try!

blog comments powered by Disqus
About

RSS

All Posts IT Ruby Padrino template inheritance Haml

Tags

GitHub projects

Twitter @botanicus

Recent Comments