Ruby: Rendering erb template

28 Oct 2014

I never used ERB outside Rails or without tilt. So while I was working with a bare rack app, I though I should try our ERB directly and checkout its api.

So I taken a look into ERB Class just enough to render a template, nothing much in detail. Here is the syntax for ERB constructor,

ERB.new(template_string, safe_eval=nil, trim_mode=nil, outvar='_erbout')

let see how we can render some template with this.

Using Sting template

Here is the simple example, for rendering a string template. Since we didn’t specify the outvar the result method will return the rendered html.

name = "Whatznear";
ERB.new("<h1>Hello ERB World!! </h1><h3><%= name %></h3>").result(binding)

Hope you noticed that we are passing binding to result method. binding gives the context in which the template to be evaluated, so they can replace the correct variables with its values.

If you like looking into details of binding, you can check the ruby doc for Binding. The above snippet will result in

<h1>Hello ERB World!! </h1><h3>Whatznear</h3>

Using template file

If you want to render a template from file, you just need to read the content of file and pass to ERB constructor.

require "erb"

class Basicerb

  def initialize name
    @name = name
    @template = File.read('./index.erb')
  end

  def render
    ERB.new(@template).result( binding )
  end
end
<%# index.erb %>
<h1>Hello ERB World!! </h1><h3><%= @name %></h3>

Here, we used @name, an instance variable because we are passing the context of Basicerb object to result method.

If you want to store the rendered html into another instance variable you can the variable as outvar.

require "erb"

class Basicerb
  attr_reader :html

  def initialize name
    @name = name
    @template = File.read('./index.erb')
  end

  def render
    ERB.new(@template, 0, "", "@html").result( binding )
  end
end

Using layout and view template

The most confusing things was rendering some erb inside an layout. Here is the layout.rb

<div class="jumbotron">
    <%= yield %>
</div>

and we use the above index.erb as view.

require "erb"

class Basicerb
  def initialize name
    @name = name
    @layout = File.read('./layout.erb')
    @template = File.read('./index.erb')
  end

  def render
    templates = [@template, @layout]
    templates.inject(nil) do | prev, temp |
      _render(temp) { prev }
    end
  end

  def _render temp
    ERB.new(temp).result( binding )
  end
end

Lets break it down how it works, The Enumerable#inject will accept a value and a block. The block will be executed for every element and the value we passed will be taken as first element. So in this case, in the first iteration, prev will be nil and temp will be the @template (view) string and pass it to _render method. Since this @template doesn’t have a yield it just render the string as before.

In the second iteration, the prev will be rendered html of @template and temp will be @layout. Then these values will be passed to _render. Now while rendering layout it have a yield method which will be replaced by rendered html of @template. And finaly the render method will return html as below.

<div class="jumbotron">
  <h1>Hello ERB World!! </h1><h3>Whatznear</h3>
</div>

Hooray, the result seems what we expected.

If you find my work helpful, You can buy me a coffee.