The very first thing we'll need is a new route to handle form submissions. Let's add a new /subscribe
route that handles a form POST submission.
post '/subscribe' do
@name = params['name']
erb :subscribe
end
All it's doing is accepting a POST request to /subscribe
, getting the entered name and saving it to an instance variable (just like Rails) and return a views/subscribe.erb
template. Since our form already submits to /subscribe
, this route will handle the form submission.
Next, let's add a simple subscribe.erb
template under the views
directory. For now, it says that new user has subscribed.
<h1>
<%= @name %> has subscribed!
</h1>
Restart the app, and submit the form after entering the name and email. You should see the following page.
Now, instead of rendering a separate /subscribe
page, we want to send a Turbo Stream that update multiple elements at the same time. For this, let's first add the Turbo library to our app, just like we did earlier. Under the <head>
tag, add the following code.
<script type="module">
import * as Turbo from 'https://cdn.skypack.dev/@hotwired/turbo';
</script>
Now that we've Turbo, we'll accomplish the multiple dynamic Turbo Stream updates in two simple steps:
Step One: Use Turbo HTTP Header
For the Turbo JavaScript library to identify the Turbo HTTP response from the server, the response needs to have a special HTTP header that indicates the Content Type, as follows:
Content-Type: 'text/vnd.turbo-stream.html'
As long as the response has this header, the Turbo library will treat it as a Turbo Stream response and treat it accordingly.
Adding a new header in Sinatra is very simple.
post '/subscribe' do
@name = params['name']
response.headers['Content-Type'] = 'text/vnd.turbo-stream.html'
erb :subscribe
end
Step Two: Send Turbo Streams in Response
Replace the existing content of the subscribe.erb
template with the following code, which contains two separate Turbo Stream responses containing following action attributes:
replace: to swap the existing content of an element with the ID
subscriber-notification
with the content inside the<template>
tag.append: to append the contents inside the
<template>
tag to the element with the IDsubscriber-list
.
<turbo-stream action="replace" target="subscriber-notification">
<template>
<div id="subscriber-notification">
<%= @name %> has subscribed!
</div>
</template>
</turbo-stream>
<turbo-stream action="append" target="subscriber-list">
<template>
<li><%= params[:name] %></li>
</template>
</turbo-stream>
If you notice the HTML that you copy+pasted earlier in the index.erb
template, it contains these two elements:
<div style="color: green; text-align: center;">
<div id="subscriber-notification"></div>
</div>
<ul id="subscriber-list">
<li>Yukihiro 'Matz' Matsumoto</li>
<li>Jason Fried</li>
</ul>
So, in its essence, we are instructing Turbo to replace the empty notification div element with another div containing the subscriber name, and to append the name of the new subscriber to the existing list.
To learn more about various Turbo Stream actions, check out its documentation.
That's it. You're all set. Restart the app, fill out the form, and hit submit. You should see the green notification as well as the name of the new subscriber.