Sinatra layouts
One of the most important principles in software engineering is to stay DRY: don’t repeat yourself.
The basic idea is that you don’t want to be copying and pasting the same code into multiple places. If you’re doing this, you’re making a lot of work for yourself should you ever decide to change that code.
One way of staying DRY that we’ll meet soon is writing functions: if there’s a task that you do repeatedly, write a function to put the logic for that task in one place and then call the function when you need to do the task.
Another way, that we’ll be looking at today, is in the form of layouts.
The Problem
In the exercise today, you’ve been using a lot of erb view templates. You have 4 different templates, which all share the same basic outline:
<!-- in views/index.erb -->
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
<link rel="stylesheet" href='/main.css'>
<title>Event Manager 2.0</title>
</head>
<body>
<div class="container">
<h1>Picture Unveiling Evening</h1>
<div class="list-group">
<a class="list-group-item list-group-item-action" href='/todo'>Todo list</a>
<a class="list-group-item list-group-item-action" href='/schedule'>Event schedule</a>
<a class="list-group-item list-group-item-action" href='/rsvps'>RSVPs</a>
</div>
</div>
</body>
</html>
<!-- in views/todo.erb -->
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
<title>Event Manager 2.0</title>
</head>
<body>
<div class="container">
<h1>Todo list</h1>
<ul class="list-group">
<% @todos.each do |todo| %>
<li class="list-group-item"> <%= todo %></li>
<% end %>
</ul>
</div>
</body>
</html
These files are almost the same - a lot of copy and paste has
gone on.
The Solution
Sinatra gets round this problem by allowing you to have a layout.erb file in your views folder:
<!-- views/layout.erb -->
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-giJF6kkoqNQ00vy+HMDP7azOuL0xtbfIcaT9wjKHr8RbDVddVHyTfAAsrekwKmP1" crossorigin="anonymous">
<link rel="stylesheet" href='/main.css'>
<title>Event Manager 2.0</title>
</head>
<body>
<div class="container">
<%= yield %>
</div>
</body>
</html
You can then write only the bits that change in the other two
views:
<!-- in views/index.erb -->
<h1>Picture Unveiling Evening</h1>
<div class="list-group">
<a class="list-group-item list-group-item-action" href='/todo'>Todo list</a>
<a class="list-group-item list-group-item-action" href='/schedule'>Event schedule</a>
<a class="list-group-item list-group-item-action" href='/rsvps'>RSVPs</a>
</div>
<!-- in views/todo.erb -->
<h1>Todo list</h1>
<ul class="list-group">
<% @todos.each do |todo| %>
<li class="list-group-item"> <%= todo %></li>
<% end %>
</ul>
Sinatra knows that if you have a file called layout.erb it should use that as a layout. If you call erb :index:
- It takes the
layout.erb file.
- It finds the bit where it says
<%= yield %>.
- It inserts
index.erb at that point. You can find more about Sinatra layouts on the internet.
New:
- If you have a file
views/layout.erb Sinatra will treat it as a layout file:
whenever it renders another template, it will try and insert the output into the
<%= yield %> part of the layout file.
From before:
- Files inside the
public folder will be served at the root of the site. This is where stylesheets and images should live.
- You call a template with the line
erb :template_name
- For this to work, you will need a template called
template_name.erb in the views folder.
- If you want to share a variable with the template, you need to make it an instance variable,
by starting the variable name with
@
- You can display these shared instance variables by using them inside an erb tag:
- Create a layout file, containing the shared material from each view.
- Remove the shared material from each view.
- Check that the screens still look the same!
Prev | Next