Fundamental ERB for Front-End Development

Henry Bley-Vroman

Posted

A version of this post appeared on viget.com

Geology: various uncut semi-precious stones. Coloured lithograph by H. Sowerby after himself, 1851. Wellcome Collection. Public Domain Mark.

ERB is the view templating language Viget's front-end developers use with Ruby On Rails. This primer is designed to bring new developers up to speed writing it.

Read more

This post is an iteration on ERB and Twig Cross-Reference for Front-End Development. That post is geared towards developers who want to translate their Twig knowledge to ERB, or vice versa. You may also be interested in Fundamental Twig for Front-End Development.

What is ERB?

ERB (Embedded Ruby) is a feature of Ruby that lets you —you guessed it!— embed Ruby in other files. ERB files have the extension .<compiled_extension>.erb. It is the language HAML and Slim are shorthand for. ERB is commonly used for templating Views in Rails apps — at Viget we use it when building large sites with custom CMSes. (If that's something you do, check out Colonel Kurtz, the block editor we often use for the client-facing admin area of Rails app sites.)

Because it can do anything Ruby can do, it's extremely powerful, has a much steeper learning curve than Twig, and can do a lot that isn't relevant to front-end templating. There's no cannonical ERB-for-front-end-developers documentation, and the Rails official documentation is immense and hard to dig through. Some resources if for learning ERB:

Reference

Delimiters

Comments

Inline comments

<%# … %>

erb
<%# comment %>
Copied

Block comments

=begin=end

the opening and closing tags must be at the start of the line

erb
<%
=begin %>
block comment
(both lines of both the begin and end tags must be at the start of their lines)
<%
=end %>
Copied

not

erb
<%
=begin %>
not a comment
<%
=end %>
Copied

Outputting values

<%= … %>

erb
<%= "print this" %> <%# output: `"print this"` %>
<%= 1 + 2 %> <%# output: `3` %>
Copied

Execution (Control Code)

<% … %>

erb
<% ifdo %> … <% end %>
Copied

Conditionals

Single-statement conditionals

if and unless

erb
<%= 2 if true %> <%# output: `2` %>
<%= 2 if false %> <%# output: `nil` %>
<%= 2 unless true %> <%# output: `nil` %>
<%= 2 unless false %> <%# output: `2` %>
Copied

Multi-statement conditionals

ifelsifend

erb
<%# assuming x, y, z, and n are defined %>
<% if x %>
y
<% elsif z == n %> <%# note the spelling of elsif %>
0
<% else %>
1
<% end %>
Copied

Conditionals with logical operators

ERB supports "condition ? iftrue : iffalse", and "ifselftrue ?: otherwise".

Note that the "then" case : must be provided

erb
<%# assuming x, y, z, and n are defined %>
<%# if x then y %>
<%# omitting the "else" will throw an error #>
<%= x ? y : '' %>
<%# if x is true, y. otherwise, if z equals n then 0. otherwise 1 %>
<%= x ? y : z == n ? 0 : 1 %>
<%# ternary operator: x if x is true, otherwise y %>
<%= x ?: y %>
Copied

Truth and falsity of zero in Boolean contexts

0 is True in Boolean contexts

erb
<%= false ? 'truthy' : 'falsy' %> <%# output: `"falsy"` %>
<%= 0 ? 'truthy' : 'falsy' %> <%# output: `"truthy"` %>
Copied

Defining variables

=

erb
<% var = 1 %>
<% anotherVar = 0 %>
<% falseVar = false %>
<%= 2 if var %> <%# output: `2` %>
<%= 2 if anotherVar %> <%# output: `2` %>
<%= 2 if falseVar %> <%# output: `` %>
<%= 2 unless falseVar %> <%# output: `2` %>
Copied

Line breaks within a variable's value

Multi-line blocks of markup can stored in an identifier with content_for x doend

erb
<% content_for longVar do %>
<div>
</div>
<% end %>
<%= content_for(longVar) %>
Copied

Note: content_for is additive: each time you provide content for a given variable, that content is appeneded to what was there already. To use content_for to overwrite a global variable, use the flush: true option:

erb
<% content_for refreshedVar do %>
a
<% end %>
<% content_for refreshedVar, flush: true do %>
b
<% end %>
Copied

Dealing with undefined variables

  • defined?()

    erb
    <%# output: the content if `var` is defined %>
    <% if defined?(var) %>
    <% end %>
    <%# output: `var` if `var` is defined, otherwise `fallback` %>
    <%= defined?(var) ? var : fallback %>
    Copied
  • ||=, the OR Equal operator

    erb
    <%# output: `var` if it is defined and not nil and not false, otherwise `fallback` %>
    <% var ||= fallback %>
    <%
    =begin %> common front-end use cases:
    1. output a variable only if it is defined
    <%
    =end %>
    <% var ||= nil %>
    <%# set a variable with a fallback %>
    <% x = y ||= nil %>
    Copied

Variable interpolation

#{var}

erb
<% x = 1 %>
<%= "this is interpolated: #{x}" %><%# output: `this is interpolated: 1` %>
Copied

Concatenation

+ (plus). Note that to concatenate a string and a number in Ruby, the number must be converted to a string.

erb
<% string_variable = 'world' %>
<% number_variable = 2 %>
<%= 'hello ' + string_variable %> <%# output: `"hello world"` %>
<%= "example #{number_variable}" %> <%# output: `"example 2"` %>
<%= 'example ' + 3.to_s %> <%# output: `"example 3"` %>
Copied

Iteration (loops)

Iterating over items

n.each do |i|end

erb
<% items = ['a', 'b', 'c'] %>
<%# output: `...` %>
<% [0..items.length].each do %>.<% end %>
<%# output: `a b c ` %>
<% items.each do |item| %>
<%= item %>
<% end %>
Copied

Using the loop index, 0-indexed

  • n.each_with_index do |i, index|end

    erb
    <%# output: `0. a 1. b 2. c ` %>
    <% items = ['a', 'b', 'c'] %>
    <% items.each_with_index do |item,index| %>
    <%= index %>. <%= item %>
    <% end %>
    Copied
  • n.times do |i|end

    erb
    <%# output: `0 1 2 3 4 5 6 7 8 9` %>
    <% 10.times do |i| %><%= i %> <% end %>
    Copied

Using the loop index, 1-indexed

  • .each_with_index's index is always 0-indexed, so add 1

    erb
    <% items.each_with_index do |item,index| %>
    <%= index + 1 %>. <%= item %>
    <% end %>
    Copied
  • n.times do |i|end

    erb
    <%# output: `1 2 3 4 5 6 7 8 9 10 ` %>
    <% 10.times do |i| %><%= i %> <% end %>
    Copied

Iterating a certain number of times

n.times do |i|end

erb
<% n = 3 %>
<%# output: `...` %>
<% n.times do %>.<% end %>
<%# output: `1 2 3 ` %>
<% n.times do |i| %>
<%= i %>
<% end %>
Copied

Inspecting data

There are several options for formatting an object's data, notably: simply outputting, .inspecting, and debug()ing. For basic data-checking purposes in a view, the essential difference is debug() returns YAML while inspect and printing return strings.

erb
<%# for some object `posts` %>
<%= posts %>
<%= posts.inspect %>
<%= debug(posts) %>
Copied

Slicing

.slice(index), .slice(start,count)

erb
<%= [1,2,3,4].slice(1) %> <%# output: `2` %>
<%= [1,2,3,4].slice(1,2) %> <%# output: `[2,3]` %>
Copied

Shorthand to slice the first count items

.take(count) or .first(count)

erb
<%= [1,2,3,4].take(2) %> <%# output: `[1,2]` %>
<%= [1,2,3,4].first(2) %> <%# output: `[1,2]` %>
Copied

Trimming whitespace

If trim_mode is set to -, a - in the closing erb tag will trim trailing whitespace:

erb
<% something -%>
1
<%= something_else -%>
2
<% another_thing %>
Copied

is equivalent to

erb
<% something %>1
<%= something_else %>2
<% another_thing %>
Copied

Keyed values

Use a Symbol :property to look up an operation on a Hash:

erb
<% myHash = {hello: 'world'} %>
<%= myHash[:hello] %> <%# output: "world" %>
Copied

Vertical inheritance

For a layout file that pulls in page: content_for in child, yield in parent

layouts/layout.html.erb

erb
<%= yield :myBlock %>
Copied

views/page.html.erb

erb
<% content_for :myBlock do %>
the content
<% end %>
Copied

Vertical inheritance with default content in the parent

layouts/layout.html.erb

erb
<% if content_for?(:my_content) %>
<%= yield :my_content %>
<% else %>
default content
<% end %>
Copied

views/page.html.erb

erb
<% content_for :my_content do %>
the content
<% end %>
Copied

Using partials

render will output the contents of another file

erb
<%= render 'path/to/x' %>
Copied

To pass values to the rendered file, define them:

erb
<% a = 1 %>
<% b = 2 %>
<%= render 'path/to/x', a:a, b:b %> <%# in path/to/x a=1 and b=2 %>
Copied

If the rendered file expects different variable names, use those:

erb
<% a = 1 %>
<% b = 2 %>
<%= render 'path/to/x', y:a, z:b %> <%# in path/to/x y=1 and z=2 %>
Copied

Related Posts

Next
Previous

See All Posts