Created: 2008-12-06 05:05
Updated: 2016-05-08 18:38



A next-gen template engine -- cause mixing ruby code and semantic html (via erb) SUCKS!!

erb was created in 1999, a 20th century technology. What is this Active Server Pages??

Ruby Template Framework for the 21st Century!


To keep html clean, simple, semantic, and separated from Ruby logic. The community focuses so much on separating css styles from html; javascript from html, then we stick a patch of logic poo, with Ruby, right in the html.

We are reducing cohesion through removing dependecy on locality, see Jim Weircach's talk: The Building Blocks of Modularity


There really is no other solution, in Ruby that follows through with this concept. has a similiar concept with code behind pages, but is convoluted with a complex page callback cycle and squirlly callbacks, too complex.

Java and PHP have similiar ideas:

  • some examples

This does not compete with Haml at all, is actually complimentary and can help clean up Haml files. subView can work in tandem with Erb!


Existing Ruby Template Engines

  • Kwartz - Erb Version II by the same author as Erb, has the right concept, implementation is horrible
  • Erector - Pivotal Builder Crap
  • Punk - Initializing but adds tags to html
  • 19 Ruby Template Engines


A ruby file compliments a html file.

This could reside in the same directory or a separte /subview directory.


The SubView Class

class Index include SubView



JOhn Doe

def initialize self.some_label.value = end

John Doe

label :some_label do |l| l.text = 'John Doe' end


<% if @order.size > 0 %> -- order table --

<% else %> Sorry no orders exist <% end %>

def initialize @orders = Order.find(:all) if @orders.size < 0 self.('#order_table').hide() end end

table :order_table do |t| @orders = DeliveryOrders.find(:all) if @orders > 0 = @orders else t.hide '#message'.show end end

  • actually removes from resulting html, not just turning off style


  • No more form helpers, set object and url in twin.
  • name in html can match object or not


this.session_form = Session this.session_form.action = new_session_path() this.session_form.login = Session.login this.session_form.password = Session.password

form :some_form do |f| customer = current_customer f.action = new_customer_path = current_customer.first_name = end

Beautiful Blocks

A generic box to encapsulate some text

def box(title = nil, *args, &block) options = args.extract_options! style = options[:style] ? " style = '#{options[:style]}'" : ''

b = "<div class="box"#{style}>#{box_label(title) if title}" e = ''

data = capture(&block) res = b + data + e concat(res, block.binding) end

<% box('Name:') do %> <%=h %> <% end %>


object_collection = Object.find(:all) object_collection.value =


  • automatically includes ruby partial view if id has _partial

_products.html _products_view.rb

  • mini-ruby code snippet

  • html include type partial

  • has reference to the Page View it is included in! allowing no passing of variables

self.products.each do |product| self.product_name = self.product_cost = currency_value(product.cost) end

Application Layout

in the SubView class you can specify your enclosing application layout

class ProductView include SubView

template :application




Amazingly easy to build Themes.

All you need is standard HTML with the right set of css tags!

No code just switch out html files.


| parameters to controller are available in View or variables set | ideally use parameters

def initalize @product = Product.find(id) self.head.meta_tag = @product.title self.head.include_javascript = auto_link end

Hooking up to the Mighty Merb


use_template_engine :sub_view

Ajax Events

Creates the plumbing for handling presentation centric ajax calls.

By just having the event method defined, underlying jquery will be generated and along with Metal will create the routing to send it to your presentation class:

event :selector, :event => :onMouseOut do |e| # e is an event class to reference addresses = Address.find(:all) end

callback javascript with the e (Event) class allowing you to pass info and

intercept view

event :selector, :event => :onMouseOut, :call => 'javaScript' do |e| addresses = Address.find(:all) end

event :some_form, :event => :onSubmit do # a no-no go to RESTful controllers end

CSS3 Selectors

Support for all CSS3 selectors

Full Example

def Index include SubView

def initialize self.h1 = $('#h1'). @address = Address.find(:first) end

def click_h1


rack routes parameters (like merb formal dynamic parameters!!)

def push name='create'


div :some_div do |d| d.inner_html = 'blah-blah' $('label').text = 'test' end

div '#some_div .ul' do |d|


table :order_table do |t| orders = DeliveryOrders.find(:all) t.partial = render_partial 'orders', :data => orders end

form :some_form do |f| customer = current_customer f.action = new_customer_path = current_customer.first_name = end

label :first_name do |l| l.text = 'yo' end

event :selector, :event => :onMouseOut, :call => 'javaScript' do |e| addresses = Address.find(:all) end

event :some_form, :event => :onSubmit do # a no-no go to RESTful controllers end


Cookies help us deliver our services. By using our services, you agree to our use of cookies Learn more