Rails 8 with Turbo morph and turbo stream

Edu Depetris

- Dec 13, 2024
  • Ruby On Rails
  • Turbo Morph
  • Tubo Stream
I was experimenting with Turbo Morph and was surprised by the number of things we can achieve with plain Ruby on Rails and a bit of Turbo Morph/Stream.

So, I decided to put together a quick example of creating a highly reactive and responsive UI without JavaScript.

This is a great video about morph.

Let’s Build the Following App:

List app


I’ll be using Rails 8 and Tailwind CSS. Here are the steps to set up everything we need:

$ rails new app --css=tailwind
$ rails g scaffold Item title:string
$ bin/rails db:migrate

Great, we have our views and models set up.

Building the Interface

First, let’s work on our interface to mimic the mockup. [Commit]

Next, let’s add a title validation to avoid creating empty items. [Commit]

Now, I’ll update the controllers to redirect to the list index action after creating an item. [Commit]

Reviewing Our Progress

Let’s have a quick look at what we have so far. Every time I delete or remove an item, Turbo comes into action and replaces the body of the page with the new HTML. Pretty cool, as it avoids a full page reload. However, there are a few things that aren’t ideal:

 1. The scroll position is not preserved.
 2. The entire body is replaced.

default-turbo-sm.mp4 1.62 MB


Enhancing with Turbo Morph

Let’s use Turbo Morph by adding the following line to the layout to address these two issues: [Commit]

<%= turbo_refreshes_with method: :morph, scroll: :preserve %>

This introduces two new meta headers:

1.  <meta name="turbo-refresh-method" content="morph">
2. <meta name="turbo-refresh-scroll" content="preserve">

with-morph-and-scroll-sm.mp4 2.15 MB


Pretty cool! We now have an incredible UX without writing a single line of JavaScript.


Handling Validation Errors with Turbo Streams

Now, let’s move on to our final step: displaying validation errors on the same index page when a user tries to create a new item without a title.

To achieve this, we’ll use Turbo Streams. The idea is to respond with a piece of HTML that renders the form with the errors.

We need to do two things:

 1. Wrap the form HTML element with an ID. I’ll use dom_id(item).

 2. Update the ItemsController#create method to respond with a Turbo Stream action.

Here’s how to modify the controller: [Commit]

format.turbo_stream do
  render turbo_stream: turbo_stream.replace(@item, partial: "form", locals: { item: @item }, method: :morph)
end


with-turbo-stream-sm.mp4 865 KB


And that’s it! We’ve built a responsive and reactive UI with Rails 8, Turbo Morph, and Turbo Streams—all without writing any JavaScript.

Happy Coding!