Passing Data Between Views and Controllers in Sinatra
Overview
In this code-along, we'll show you how to pass data back to views from your controller using an instance variable, and then render it using ERB.
Objectives
Pass data from a form to a controller using
params
Manipulate data inside of a route in the controller
Assign data to an instance variable
Render data in a
.erb
file using erb tags
Setup
Why is passing data back to views from your controller so important? It allows us to make your pages dynamic rather than static - that is, the data can change depending on the inputs provided by the user. As an example, we'll be creating a "String Reverser" - the user inputs a string ("Hello World") into an HTML form, and is shown the reverse of the string ("dlroW olleH") on the following page.
To code along, fork and clone this repository. Run bundle install
from the command line to ensure you have the proper dependencies installed. The starter code contains a basic Sinatra application which you can access by running shotgun
in your command line and then opening http://localhost:9393/reverse
in your browser.
Starter Code
Let's take a closer look at the starter code.
Views
reverse.erb
has a form that has one text input tag:<input type="text" name="string">
. Remember that the name attribute becomes the key for the form data in theparams
hash. The form has a method attribute ofPOST
, and an action attribute of/reverse
.reversed.erb
which will eventually show the reversed version of the string submitted by the user.friends.erb
, which we'll be using to talk about iteration in erb.Note: The views all have basic CSS styling (linked using the
<link
> tag) that can be found instyle.css
in thepublic/stylesheets
folder.
Routes
The controller has three routes:
get '/reverse' do
, which renders thereverse.erb
page.post '/reverse' do
, which receives that params hash from the form (but does nothing with it) and renders thereversed.erb
page.get '/friends' do
, which renders thefriends.erb
page.
Manipulating Params in the Controller
Let's start by taking a look at our params when we submit the form on the /reverse page. The easiest way to do this is to find the post route to which the form is sending data - in this case post /reverse do
- and add a puts params
inside the method:
When we submit the form, the contents of params will output in the console. Let's submit "hello friend" to the form and look at params
in our console:
To manipulate the string, let's take it out of the params hash, and then call the .reverse
method on it:
We now have a reversed version of the original string submitted by the user. Great! But it's in our controller, which our user will never see. How do we pass this data back in to a view?
Using Instance Variables
Instance variables allow us to bypass scope between the various methods in a class. Creating an instance variable in a controller method (route) lets the contents become 'visible' to the erb file to which it renders. Instead of creating a local variable reversed_string
, change it to an instance variable @reversed_string
.
We can now access the contents of @reversed_string
inside of our view, reversed.erb
.
Note: Instance variables are ONLY passed from the controller method where they are created to the view that is rendered, not between controller methods. For example:
Rendering using ERB tags
Right now the content of reversed.erb
is just plain old vanilla HTML in a .erb file. In order to show the content of a Ruby string, we need to use erb tags. As a recap:
<%= contents %>
will display the evaluated expression within the opening and closing.<% contents %>
will evaluate the contents of the expression, but will not display them.
We know that the contents of @reversed_string
are available to the erb file, so let's put them together:
Notice that we've put the erb tag with @reversed_string
within <h2>
tags. Just some additional styling!
Iterating in ERB
We have one additional get
request that we're going to use to practice sending data from the controller to a view. In this case, we want to assign an array (rather than a string) to an instance variable. Let's create an array called @friends
inside of the get '/friends' do
route, and render the friends.erb
page:
In friends.erb, we want to show each item in the array inside of its own <h2>
tag. Unfortunately this won't work:
Instead, we'll have to use iteration with the .each
method to loop through each item in the array and put it in its separate <h2>
tag. Let's start with the iterator - notice that we're using erb tags that don't display the evaluated expression:
Next, let's set up what we want to do for each item:
This will set up a loop through all items in @friends
and then place each item in the array in its own <h2>
tag. The rendered HTML will look like this:
You can imagine how powerful iteration in erb is when you have an array of thousands of items that you have to display in your view!
Last updated