Fundamental ERB for Front-End Development

Your comprehensive guide for ERB front-end view templates.
Geology: various uncut semi-precious stones. Coloured lithograph by H. Sowerby after himself, 1851
Geology: various uncut semi-precious stones. Coloured lithograph by H. Sowerby after himself, 1851. Sowerby, Henry, 1825-1891. Public Domain Mark. Source: Wellcome Collection.

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.

Contents

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.

Because it can do anything Ruby can do, it’s extremely powerful, has a steeper learning curve than languages intended for front-end templates specifically, 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
erb
<%# comment %>
erb
<%# comment %>

Block comments

=begin=end

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

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

not

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

Outputting values

<%= … %>

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

Execution (Control Code)

<% … %>

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

Conditionals

Single-statement conditionals

if and unless

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

Multi-statement conditionals

ifelsifend

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

Conditionals with logical operators

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

Note that the “then” case : must be provided

erb
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 %>
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 %>

Truth and falsity of zero in Boolean contexts

0 is True in Boolean contexts

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

Defining variables

=

erb
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` %>
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` %>

Line breaks within a variable’s value

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

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

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
erb
<% content_for refreshedVar do %>
a
<% end %>
<% content_for refreshedVar, flush: true do %>
b
<% end %>
erb
<% content_for refreshedVar do %>
a
<% end %>
<% content_for refreshedVar, flush: true do %>
b
<% end %>

Dealing with undefined variables

  • defined?()

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

    erb
    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 %>
    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 %>

Variable interpolation

#{var}

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

Concatenation

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

erb
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"` %>
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"` %>

Iteration (loops)

Iterating over items

n.each do |i|end

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

Using the loop index, 0-indexed

  • n.each_with_index do |i, index|end

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

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

Using the loop index, 1-indexed

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

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

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

Iterating a certain number of times

n.times do |i|end

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

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
erb
<%# for some object `posts` %>
<%= posts %>
<%= posts.inspect %>
<%= debug(posts) %>
erb
<%# for some object `posts` %>
<%= posts %>
<%= posts.inspect %>
<%= debug(posts) %>

Slicing

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

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

Shorthand to slice the first count items

.take(count) or .first(count)

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

Trimming whitespace

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

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

is equivalent to

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

Keyed values

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

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

Vertical inheritance

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

layouts/layout.html.erb

erb
erb
<%= yield :myBlock %>
erb
<%= yield :myBlock %>

views/page.html.erb

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

Vertical inheritance with default content in the parent

layouts/layout.html.erb

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

views/page.html.erb

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

Using partials

render will output the contents of another file

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

To pass values to the rendered file, define them:

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

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

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

Articles You Might Enjoy

Or Go To All Articles