DEV Community

nicho1991
nicho1991

Posted on

How to - Rails turbo

Why turbo

NO JS ?!

Image description

When your application needs to be more 'dynamic' than the simple old school 1 request 1 view, you would typically use javascript, or a complete javascript framework like React to turn the page into a Single Page Application, however this is cumbersome, especially in the rails spirit of the ability to maintain the stack as one developer.

Turbo reduces the requirements for javascript in your rails application, and makes it more like a single page application ( although, this is by far not a replacement for that )

This a quick 'how to' run and use turbo in a rails application
How to use turbo on rails, credit goes to https://hotwired.dev/, you can also checkout https://turbo.hotwired.dev/handbook/introduction for the documentation on turbo

Requirements

Minimum rails 6 app ( it is installed automatically on a rails 7 app ), to install on rails 6 refer to https://github.com/hotwired/turbo-rails#:~:text=Add%20the%20turbo,Turbo%20Stream%20broadcasting.

Step by step process from scratch in a rails 7 app.

Prerequisites
rails -v
Rails 7.0.2.4

and
ruby -v
ruby 3.0.0p0

Otherwise refer to https://guides.rubyonrails.org/getting_started.html for getting set up with rails on your machine

run rails new turbo-example

Make sure it works by cd turbo-example and running rails s
You should see something like Listening on http://localhost:3000/items

Next, let's make a simple model 'item'

rails g scaffold Item title:string description:text and rake db:migrate

navigate browser to http://localhost:3000/items or whatever url you have, and you should be able to see the very empty item list.

Turbo_frame

go to app/views/items/index.html.erb and wrap the last line 'new item' to be

<%= turbo_frame_tag "new_item" do %>
  <%= link_to "New item", new_item_path %>
<% end %>
Enter fullscreen mode Exit fullscreen mode

now go to app/views/items/new.html.erb and wrap the form render like this

<%= turbo_frame_tag "new_item" do %>
  <%= render "form", item: @item %>
<% end %>
Enter fullscreen mode Exit fullscreen mode

We now have a turbo frame on our items list in the index, you can see that the page does not reload on clicking new item, or on create. However, you have to refresh to actually see the new item.

for that we can use turbo_stream

Turbo_stream

go to app/views/items/index.html.erb
and add <%= turbo_stream_from @items %> above the items div
so it looks like

<h1>Items</h1>

<%= turbo_stream_from @items %>

<div id="items">
  <% @items.each do |item| %>
    <%= render item %>
    <p>
      <%= link_to "Show this item", item %>
    </p>
  <% end %>
</div>


<%= turbo_frame_tag "new_item" do %>
  <%= link_to "New item", new_item_path %>
<% end %>
Enter fullscreen mode Exit fullscreen mode

next go to app/models/item.rb and add broadcasts

This lets the model broadcast everything happening to it (create update and delete) Note that this is regardless of any authorization rights, so keep that in mind.

now go to app/controllers/items_controller.rb#create
and add format.turbo_stream to the successful save render
it should look like this

  def create
    @item = Item.new(item_params)

    respond_to do |format|
      if @item.save
        format.turbo_stream
        format.html { redirect_to item_url(@item), notice: "Item was successfully created." }
        format.json { render :show, status: :created, location: @item }
      else
        format.html { render :new, status: :unprocessable_entity }
        format.json { render json: @item.errors, status: :unprocessable_entity }
      end
    end
  end
Enter fullscreen mode Exit fullscreen mode

lastly create app/views/items/create.turbo_stream.erb with the content <%= turbo_stream.prepend "items", @item %>

Notice the form is still the same, we can fix this by adding
<%= turbo_stream.replace "new_item", partial: 'items/form', locals: { item: Item.new } %>
in the app/views/items/create.turbo_stream.erb

the file will look like this

<!-- Refresh preview list -->
<%= turbo_stream.prepend "items", @item %>

<!-- Reset form -->
<%= turbo_stream.replace "new_item", partial: 'items/form', locals: { item: Item.new } %>


Enter fullscreen mode Exit fullscreen mode

You can find an example project of this exact step-by-step guide on https://github.com/nicho1991/turbo-example

Discussion (0)