Hotwire Handbook Learn the basics of HTML Over the Wire with practical projects Akshay Khot

  • Move Introduction to Hotwire
    Open Introduction to Hotwire

    Introduction to Hotwire

    Introduction to Hotwire
  • Move Traditional Web Architecture
    Open Traditional Web Architecture

    To understand Hotwire, we first need to know how a typical request-response cycle works when a browser requests a web page.

    When you go to a website in the browser or click a link on a page, it makes a GET request to the server, which sends an HTML response to the requesting browser. The browser then parses the HTML and displays the web page.

    request-response.png

    The advantage of this simple architecture is that most of the application logic stays on the backend, where you’re free to choose any language you like, such as Ruby, PHP, or even JavaScript.

    When you need some client-side interactivity, you sprinkle some JavaScript (or use JQuery) to get the job done. The pages load much faster, as the browser only has to render an HTML response without loading and parsing big JavaScript frameworks.

    However, a disadvantage of traditional web applications is that **the br

    Traditional Web Architecture 279 words
  • Move Single Page Applications
    Open Single Page Applications

    Single Page Applications get a lot of their speed and responsiveness from not constantly reloading the browser, tearing down the application process, only to reinitialize it on the very next page.

    These are web applications making heavy use of JavaScript, using frameworks like ReactVue, or Ember. The initial page contains all the JavaScript to make the application work, and it behaves like a desktop application. Hence these websites are called Single-Page Applications.

    Instead of fetching an HTML response from the server, these JavaScript frameworks ask for the JSON data, interpreting and rendering the JSON on the frontend. The browser doesn’t have to reload the whole page; JavaScript does most of the work.

    request-response-json.png

    A good example of a single-page application is the Rails forum powered by [Disc

    Single Page Applications 683 words
  • Move What is Hotwire?
    Open What is Hotwire?

    Hotwire stands for HTML over the wire. It is a suite of front-end frameworks shipped with Rails that tries to get the best of both worlds, keeping the original, simple web architecture of sending HTML over the wire, while not losing the performance benefits of Single Page Applications.

    hotwire.png

    Hotwire is not a single framework; it’s a suite of different frameworks that allow you to send HTML responses over the wire.

    1. Turbo uses different techniques to reduce the amount of JavaScript most web applications have to write. Turbo lets you send HTML from the server (both in response to user interaction, such as clicking links or submitting forms, or via WebSockets) which updates parts of the page dynamically, without any custom JavaScript.

    2. Stimulus is a JavaScript framework when you absolutely need to use (or sprinkle, [as DHH would say](https://world.hey.com/dhh/the-one-pers

    What is Hotwire? 488 words
  • Move Turbo Drive
    Open Turbo Drive

    In its essence, Turbo Drive intercepts all clicks on anchor links to the same domain and updates the page without a full-reload.

    When you click a link, Turbo Drive does the following:

    1. Prevent the browser from following the link,

    2. Change the browser URL using the History API,

    3. Request the new page using a fetch request

    4. Render the response HTML by replacing the current <body> element with the response and merging the <head> element’s content.

    The JavaScript window and document objects as well as the <html> element persist from one rendering to the next.

    The same goes for an HTML form. Turbo Drive intercepts and converts Form submissions into fetch requests. Then it follows the redirect and renders the HTML response.

    As a result, your browser doesn’t have to reload, and the website feels much faster and more responsive, just like a single-page application.

    That's the essence of how Turbo Drive works. **You get a bulk of the benefits of modern single-page app

    Turbo Drive 189 words
  • Move Turbo Frames
    Open Turbo Frames

    We've seen how Turbo Drive can make your website responsive by replacing the current body element with the response body.

    turbo-drive.png

    For most websites (that are not web applications), this is absolutely enough to get the majority of performance boost and to give that SPA-like feel without any added complexity.

    However, sometimes you have a website that only needs to update a small section on the page while leaving the whole page intact. In such cases, updating the whole body feels very inefficient.

    Imagine a blog with comments enabled (just like this course page you're reading this lesson on). When someone adds a comment to my post, I only want to update the comments section, without updating the whole blog post. Replacing the whole body doesn't make sense here.

    This is the appeal behind single-page applications, where most of the page remains as it is, and only sections on the page are updated independently.

    **What if yo

    Turbo Frames 515 words
  • Move Turbo Streams
    Open Turbo Streams

    Using Turbo Streams, you can send snippets of HTML content to the page and replace or modify the existing content on the page. It's specifically designed for the situations where we want to update multiple parts of the page in response to a single request.

    Turbo Streams deliver page changes as fragments of HTML wrapped in <turbo-stream> tags. Each stream element specifies an action together with a target ID to declare what should happen to the HTML inside it.

    turbo_streams.png

    Turbo streams also work great with WebSockets, but we can ignore it for now.

    In its essence, a Turbo Stream is HTML content wrapped in the <turbo-stream> tag as well as a <template> tag. The <turbo-stream> tag also contains an action and a target attribute. The action attribute instructs the Turbo framework what to do with this snippet, and the target attribute helps Turbo f

    Turbo Streams 302 words
  • Move Turbo Frames vs. Turbo Streams
    Open Turbo Frames vs. Turbo Streams

    At first glance, there doesn't seem to be any difference between Turbo frames and Turbo Streams, other than Turbo Streams let you stream live updates via WebSockets.

    However, the really cool thing about Turbo Streams is that they let you target and update multiple, unrelated parts on your page in one response. This lets your application REALLY behave like a single-page application. In comparison, Turbo Frames only allow you to target a single element (frame) at a time.

    Another big difference between the two is that Turbo Frames can only let you replace the existing frame. They won't let you append, or prepend to existing content. You can't remove any elements on the page as well.

    Finally, a common misconception regarding Turbo Streams (I used to think this, too) is that it can only be used with WebSockets to send live updates. This is not true. You can use it on POST requests after form submissions or button clicks to update multiple elements on your website. You can also use them on GET

    Turbo Frames vs. Turbo Streams 387 words
  • Move You Don't Need Rails to Start Using Hotwire
    Open You Don't Need Rails to Start Using Hotwire

    You Don't Need Rails to Start Using Hotwire

    You Don't Need Rails to Start Using Hotwire
  • Move Introduction
    Open Introduction

    Although it works great with Rails, you don't really have to use Rails (or Ruby) to get most of the benefits of Hotwire. Most static websites can just drop-in the Turbo library to behave like responsive single-page applications, without incurring any of the costs and complexities associated with the SPA frameworks.

    If you have an existing app written in PHP, Go, Rust, or even Java, you can start using Hotwire, right now. All you have to do is follow certain conventions.

    This lesson is divided into two parts:

    1. Learn how you can use the first two Hotwire techniques (Turbo Drive and Turbo Frames) in a simple static website, to fetch and update entire web pages or parts of the page, without fully-reloading the browser. We'll use a simple static site to demo this.

    2. Learn how to tweak your existing back-end code to send Turbo Streams to update multiple parts on your website dynamically, in resp

    Introduction 220 words
  • Move Project Setup
    Open Project Setup

    In this section, we'll set up a simple website that serves static files. Both Turbo Frames and Turbo Drive don't need a backend server, so a simple static website should be simple and barebones enough to explain the basic concepts.

    Create a brand new directory for your website and cd into it. I'll call mine wireframe.

    ➜ mkdir wireframe
    ➜ cd wireframe
    

    Run the npm init command to set up a new project. It will ask you a bunch of questions and then create a package.json in the current directory.

    ➜ wireframe npm init
    
    package name: (wireframe)
    version: (1.0.0)
    description: Using Hotwire without Ruby on Rails
    entry point: (index.js)
    test command:
    git repository:
    keywords: hotwire, turbo
    author: AK
    license: (ISC) MIT
    

    Here's the resulting package.json file

    {
      "name": "wireframe",
      "version": "1.0.0",
      "description": "Using Hotwire without Ruby on Rails",
      "main": "index.js",
      "scrip
    
    Project Setup 376 words
  • Move Using HTTP Server for Static Pages
    Open Using HTTP Server for Static Pages

    I am going to use a simple static HTTP server called http-server which is more than sufficient for our needs.

    http-server is a simple, zero-configuration command-line static HTTP server. It is powerful enough for production usage, but it's simple and hackable enough to be used for testing, local development and learning.

    Did you know that you can run the package without installing it first, using the npx command?

    Run the following command from the wireframe directory.

    ➜ npx http-server
    
    Starting up http-server, serving ./public
    
    http-server version: 14.1.0
    
    Available on:
      http://127.0.0.1:8080
      http://10.0.0.182:8080
    Hit CTRL-C to stop the server
    

    Without any arguments, the above command serves the index.html file in the public directory when you visit http://127.0.0.1:8080 or localhost:8080. This is why I'd asked you to create a public/index.html file for your project.

    You can also add the above command a

    Using HTTP Server for Static Pages 177 words
  • Move Installing Turbo
    Open Installing Turbo

    We are going to use the pre-compiled, optimized NPM package from skypack.dev using the <script> tag, just like it's 2007. For other installation methods, check out the Installing Turbo documentation.

    Step 1: Add the following script tag just above the <title> tag in your HTML.

    <script type="module">
      import * as Turbo from 'https://cdn.skypack.dev/@hotwired/turbo@7.1.0';
    </script>
    
    <title>Wireframe</title>
    

    Step 2: There's no step 2. 😉

    If you're curious about how the above snippet works, I highly recommend you read the MDN documentation on JavaScript Modules.

    That's it. Our little website is using Turbo.

    To verify, reload the browser, open the DevTools window, go to the Console tab, and type Turbo in it. If it doesn't throw an error, you're good to go.

    ![installing_turbo.png](https://books.writesoftwarew

    Installing Turbo 132 words
  • Move Faster Navigation with Turbo Drive
    Open Faster Navigation with Turbo Drive

    It just works out-of-box.

    The best thing about Turbo Drive is that you get it for free. Yes, you heard that right. You don't have to do anything to get the benefits of Turbo Drive.

    Let's Add a Contact Page

    To see how Turbo Drive works, we need to set up another page on our website that we'll add a link to.

    We've already added the links to the Contact and About pages when we wrote the initial HTML, so let's go ahead and add a Contact page. To keep it really simple, I'll just copy and paste the index.html page, changing the filename and a little content to make it unique.

    This is only for demo. Your back-end framework or static-site generator uses a templating system to extract all the duplicate HTML.

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <link rel="stylesheet" href="https://cdn.simplecss.org/simple.min
    
    Faster Navigation with Turbo Drive 589 words
  • Move Dynamic Page Updates with Turbo Frames
    Open Dynamic Page Updates with Turbo Frames

    I will demonstrate Turbo Frames by building a simple gallery on our home page. Here's how the resulting page will look.

    gallery-1.png

    Let's get started. First, update the index.html page's <main> tag with the following HTML. Just copy and paste it, I'll explain what's going on soon. All I did is added an image and the link, and wrapped them in a <turbo-frame> tag.

    <main style="text-align: center;">
      <h1>Gallery</h1>
      <turbo-frame id="gallery">
        <img src="images/ocean.jpeg" alt="Ocean" width="500" height="400">
    
        <div>
          <a href="/gallery/forest">Next (forest)</a>
        </div>
      </turbo-frame>
    </main>
    

    Then create a new folder named gallery in the public directory. It contains three HTML files named forest.htmlmountains.html, and ocean.html. Here's their content.

    <!-- forest.html -->
    
    <turbo-frame id="gallery">
      <img src="images/forest.jpeg" alt="forest" width="500" 
    
    Dynamic Page Updates with Turbo Frames 628 words
  • Move Setup for Turbo Streams
    Open Setup for Turbo Streams

    I'll demo the Turbo Streams with a different example, since you need to handle form submissions for Turbo Streams, and our static site can't do that. So I'll use Sinatra, an elegant Ruby web framework.

    Create a Sinatra Project

    First, let's install the Sinatra framework and Puma web server using the gem install command.

    gem install sinatra
    gem install puma
    

    Create a new directory for the project. I'll call mine wirestream. Navigate into it and open it in your favorite browser.

    mkdir wirestream
    cd wirestream
    code .
    

    Create a new Ruby script called app.rb that adds a route for the home page.

    require 'sinatra'
    
    get '/' do
      'Sinatra says hello!'
    end
    

    Now run that script just like any other Ruby script:

    ruby app.rb
    

    Sinatra is up and running and serving your web application at localhost:4567.

    sinatra.png

    **That's it.

    Setup for Turbo Streams 390 words
  • Move Targeting Elements with Turbo Streams
    Open Targeting Elements with Turbo Streams

    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.

    subscriber.png

    Now, instead of rendering a separate /subscribe page, we want to send a Turbo Stream that update multiple elements at th

    Targeting Elements with Turbo Streams 471 words
  • Move Let's Build a To-Do List with Hotwire
    Open Let's Build a To-Do List with Hotwire

    Let's Build a To-Do List with Hotwire

    Let's Build a To-Do List with Hotwire
  • Move Introduction
    Open Introduction

    There’s nothing like building a simple, run-of-the-mill to-do list when learning a new framework. It teaches you the basics of creating, reading, updating, and deleting data from various levels of the technology stack, including the front-end, back-end, and database.

    Here's a list of topics this chapter covers:

    1. Create a New Rails Application

    2. Install Tailwind CSS

    3. Create, Read, Update, and Delete Tasks

    4. How Turbo Drive Works

    5. Using Stimulus for Completing Tasks

    6. Introducing Turbo Frames for In-Place Editing

    7. Conclusion: Why Hotwire?

    We will start with a new Rails app from scratch and learn about Hotwire as we build our application. I am also going to use Tailwind CSS to style our app, but it’s not a requirement, and the code examples should still work without it. But, if you haven’t worked with Tailwind, I highly recommend that you give it a try.

    Before we start coding, this is a quick preview of what we are going to build. It’s a si

    Introduction 247 words
  • Move Step 1: Create a New Rails App
    Open Step 1: Create a New Rails App

    Run the following command to create a new Rails application in a new terminal window. I will call my app taskify.

    ➜ rails new taskify --css=tailwind
    ➜ cd taskify
    

    Open the app in your favorite editor. I will use VS Code.

    ➜ code .
    

    Let’s run the app to make sure everything is set up correctly. Use the following command to start the server and visit the http://localhost:3000 URL to see your app.

    ➜ bin/dev
    

    If everything works, Rails should greet you with the following screen.

    rails_welcome_page.png

    Step 1: Create a New Rails App 90 words
  • Move Step 2: Install Tailwind CSS
    Open Step 2: Install Tailwind CSS

    Update: Rails now ships with a generator for Tailwind CSS, so this lesson might not be relevant anymore. However, I've decided to leave it for those with older Rails versions or are following the old tutorial.

    You can build this app using plain CSS or SASS, but I highly suggest that you consider using Tailwind CSS. It will dramatically increase your productivity when designing UI (not constantly switching back and forth between HTML and CSS) and help you write more maintainable CSS.

    Now I have to warn you first if you have never seen Tailwind. It takes a while to get used to, but once you've taken the pill, you will never want to go back. I surely don't. That said, if you don’t want to use it, the rest of the tutorial should still work for you.

    First, install the tailwindcss-rails gem that makes the setup painless.

    ➜  bin/bundle add tailwindcss-rails
    

    Then run the Tailwind installer, which will set up Tailwind for you, additionally setting up `fore

    Step 2: Install Tailwind CSS 345 words
  • Move Step 3: Create the Task Resource
    Open Step 3: Create the Task Resource

    Now, we could take the easy way out and generate a rails scaffold instead of a resource, which will set up everything for us, including the routes, controller actions, views, style, etc. However, we want to really learn how to build this task manager step-by-step, so we will take the long and hard route. I promise that it's worth the effort, and you will learn a lot in the process.

    What's a resource? A resource is any object that you want users to be able to access via URI and perform CRUD (create, read, update, delete) operations on.

    We need a Task resource for our to-do list, which has description and completed attributes. So let’s generate the Task model using the rails generate resource command. This command creates an empty model, controller, and migration to create the tasks table.

    ➜  bin/rails generate resource task description:string{200} completed:boolean
    

    Running this command will create a 20220212031029_create_tasks.rb migration file under the db/migrate d

    Step 3: Create the Task Resource 259 words
  • Move Step 4: Setup the Home Page
    Open Step 4: Setup the Home Page

    Let's change the routes.rb file to change the home page to the tasks page instead of the Rails welcome page. For this, open the routes.rb file and add the following directive at the top.

    Rails.application.routes.draw do
      root "tasks#index"
    
      resources :tasks
    end
    

    Rails recommends putting the root route at the top of config/routes.rb, as it will be matched first, since a home page is the most popular route of most Rails applications.

    Now restart your Rails app, and reload the browser. You should see an error.

    unknown_action.png

    Rails throws this error because we haven’t created our index action yet. Let's create that now.

    In addition to the migration, the rails generate resource command should have also created an empty TasksController for you.

    class TasksController < ApplicationController
    end
    

    Let’s create our first action called index to display all the tasks. In th

    Step 4: Setup the Home Page 223 words
  • Move Step 5: Create New Tasks
    Open Step 5: Create New Tasks

    A task manager without any tasks is boring. So let’s add a form using which the users can add new tasks.

    Start by creating a new task in the index action on our TasksController. Our form will use this as the default task.

    class TasksController < ApplicationController
      def index
        @tasks = Task.all
        @task = Task.new
      end
    end
    

    Next, we will create the form partial by adding a _form.html.erb file in the app/views/tasks directory. This form has an input field and a button to submit the task.

    <%= form_with(model: task, class: "mb-7") do |form| %>
      <div class="mb-5">
        <%= form.text_field :description, placeholder: "Add new task", class: "inline-block w-96 px-3 py-2 mt-2 shadow rounded-md border border-gray-200 outline-none" %>
        <%= form.submit "Save", class: "btn py-2 ml-2 bg-blue-600 text-white" %>
      </div>
    <% end %>
    

    Add the following code to the index.html.erb file to display this form partial on the home page.

    <h1 class="font
    
    Step 5: Create New Tasks 687 words
  • Move Wait, Where's Hotwire?
    Open Wait, Where's Hotwire?

    At this point, you might be wondering, "Hey, you said we were going to use Hotwire in this tutorial. When are we going to get to that part?" If so, I have a surprise for you. We are already using Hotwire. At least, a sub-framework of Hotwire called Turbo Drive, which is activated by default in a Rails 7 app.

    Notice that the browser is not doing a full page reload when we add a new task. It also feels very responsive. The server redirects you to the index page whenever you click the button. However, you can see that the browser is not reloading the page, and your task shows up automatically. What gives?

    The answer is the Turbo Drive framework that’s part of the Hotwire stack. It’s working behind the scenes to make your application faster.

    To see how the app will behave without Hotwire, disable Turbo Drive by adding the following line in the app/javascript/application.js file.

    Turbo.session.drive = false
    

    Now if you try to add

    Wait, Where's Hotwire? 319 words
  • Move Step 6: Using Stimulus for Completing Tasks
    Open Step 6: Using Stimulus for Completing Tasks

    First, let’s wrap our task in a form to add a checkbox. Add the following code in the _task.html.erb file.

    <div class="block">
      <%= form_with(model: task, class:"text-lg inline-block my-3 w-72") do |form| %>
        <%= form.check_box :completed,
                           class: "mr-2 align-middle bg-gray-50 border-gray-300 focus:ring-3 focus:ring-blue-300 h-5 w-5 rounded checked:bg-green-500" %>
        <%= task.description %>
      <% end %>
    </div>
    

    Reloading the page shows the beautiful checkbox next to our task.

    checkbox.png

    Next, we will add a data-controller attribute in our index.html.erb template.

    In Stimulus, we mark our elements of interest by annotating their data attributes, such as data-controller and data-action.

    **Stimulus continuously monitors the page waiting for HTML data-controller attributes to appear. For each attribute, Stimulus looks at the attribute’s value to find a corresponding controll

    Step 6: Using Stimulus for Completing Tasks 820 words
  • Move Step 7: Edit and Delete Tasks
    Open Step 7: Edit and Delete Tasks

    As the last step, we will allow the users of our task manager to edit and delete their tasks. Let’s start by adding the corresponding actions in the tasks_controller.rb file. This is standard Rails, so I won't go too deep here.

    class TasksController < ApplicationController
      def edit
        @task = Task.find(params[:id])
      end
    
      def update
        @task = Task.find(params[:id])
        respond_to do |format|
          if @task.update(task_params)
            format.html { redirect_to tasks_url, notice: "Task was successfully updated" }
          else
            format.html { render :edit, status: :unprocessable_entity }
          end
        end
      end
    
      def destroy
        @task = Task.find(params[:id])
        @task.destroy
        redirect_to tasks_url, notice: "Post was successfully deleted."
      end
    end
    

    The edit action finds the task that we want to edit, and the corresponding view displays the edit form. Add the edit.html.erb file in the app/views/tasks directory with the following code.

    <d
    
    Step 7: Edit and Delete Tasks 301 words
  • Move Step 8: Using Turbo Frames for In-Place Edits
    Open Step 8: Using Turbo Frames for In-Place Edits

    Let's try to edit a task with the DevTools' Network tab open. Notice that the server builds and sends the whole response HTML, which is about 5.2 kB. Upon receiving the response HTML, Turbo Drive extracts and replaces the body.

    edit-1.png

    Let's improve this functionality by rendering the edit form in-place on the index page, instead of taking the user to a separate page. We will achieve this in three simple steps using Turbo Frames.

    Highlight the Turbo Frames

    Well, this is an optional step, but it will make understanding Turbo Frames easy. Turbo Frames are just custom HTML elements and are invisible by default. During development, it's useful to highlight them to understand what's going on.

    Let's add some CSS to make them visible. Add this code in the app/assets/stylesheets/application.css file.

    turbo-frame {
      border: 1px solid ligh
    
    Step 8: Using Turbo Frames for In-Place Edits 620 words
  • Move Progressive Application Development with Hotwire
    Open Progressive Application Development with Hotwire

    Progressive Application Development with Hotwire

    Progressive Application Development with Hotwire
  • Move Introduction
    Open Introduction

    If you're a web developer, you must have heard the terms Progressive Enhancement and Progressive Web Apps (PWAs). What about progressively building your web application, introducing advanced techniques only when needed?

    I recently listened to an episode of the Full-Stack Radio (Building HEY with Hotwire), where David Heinemeier Hansson talked about progressive web application development using Hotwire:

    Start with the absolute simplest. Don't even do Frames, don't even do anything. Do Turbo Drive to start, just build the thing with normal forms, normal everything, and when you run into issues like... this part is reset everytime I add new stuff. What's the smallest thing I could do to fix that? Alright, let's do a frame.

    After some time, it's getting too complicated and you need more fidelity, o

    Introduction 389 words
  • Move Step 1: Setting up the Rails App
    Open Step 1: Setting up the Rails App

    Let's create a new Rails app named daily-habits, and launch it using the bin/dev command. Note that I am using Tailwind CSS for styling the components.

    $ rails new daily-habits --css=tailwind
    
    $ cd daily-habits
    
    $ bin/dev
    

    We'll start by creating the core data model for our application: a Habit.

    Step 1: Generate the Habit Model

    The very first thing that we're going to do is to generate a model named Habit with two properties: name and count indicating the name of the habit and how many days you've followed that habit.

    $ bin/rails generate model habit name:string count:integer
    

    After running this command, Rails will generate a few files for you, including a database migration file. Let's run the database migration, so a habits table is created in the database.

    $ bin/rails db:migrate
    

    Now open the Rails console and create a sample habit named 'Write Every Day', because writing is awesome and you all should write every day.

    Step 1: Setting up the Rails App 193 words
  • Move Step 2: Setting a Route to Show the Habit
    Open Step 2: Setting a Route to Show the Habit

    Open the config/routes.rb file and add a new route to it.

    Rails.application.routes.draw do
      resources :habits, only: [:show]
    end
    

    This route instructs Rails to call the show action method on the HabitsController class, when a user visits the path /habits/1. You can also access this route programmatically using the URL helper named habit_path, passing an instance of Habit model.

    If you want to learn routing in detail, check out the following article: Understanding the Rails Router: Why, What, and How

    Now that we have a valid route to show the habit, we need a controller and action to handle the incoming request.

    Step 2: Setting a Route to Show the Habit 95 words
  • Move Step 3: Create a Controller and Action
    Open Step 3: Create a Controller and Action

    Let's use a generator to generate a HabitsController class with a show action.

    $ bin/rails generate controller habits show
    

    It will generate quite a few files, but we're only interested in the controller class. Edit the show action on the HabitsController class to set up an instance of habit.

    class HabitsController < ApplicationController
      def show
        @habit = Habit.first
      end
    end
    

    At this point, we have a habit to show in our views, which we'll tackle next.

    Step 3: Create a Controller and Action 72 words
  • Move Step 4: Create a View to Render the Habit
    Open Step 4: Create a View to Render the Habit

    Before building the view to show a habit, we'll tweak the application layout that Rails generated for us, so we have a nice area in the middle of the page to work with.

    Open the application.html.erb file under the views directory, and update the <main> tag to add the following classes.

    <main class="mx-auto mt-28 w-96 p-5 border rounded">
      <%= yield %>
    </main>
    

    Don't worry if they look confusing. All we're doing is center-aligning the main tag (with mx-auto and w-96), adding some padding (p-5) and margin (mt-28), and wrapping it inside a rounded border. Makes sense?

    Now that we have a sandboxed area to play with, let's add a view to display the habit. For the HabitsController#show action, Rails will assume the location of the view file to be under views/habits directory, in a file named show.html.erb.

    Let's open that file and add the following code to it. To add some extra spice to our habit tracker, I've added the streak markers below the habit, similar to h

    Step 4: Create a View to Render the Habit 477 words
  • Move Building with Turbo Drive
    Open Building with Turbo Drive

    The magic of Turbo Drive is that you don't even notice it. It's just there, in the background, making your navigation faster.

    In this section, we'll make the counter work by updating the count when you press the buttons.

    We're going to use the buttons (embedded inside forms) to increment and decrement the counter. Whenever the user presses the buttons, it will submit the form to the backend, which will update the habit count, and redirect to the updated habit.

    As mentioned earlier, Turbo Drive will follow the redirect and update the whole body with the new response, all without reloading the browser.

    Enough talking. Let's write some code.

    Step 1: Create Routes to Update the Counter

    Let's create two new routes to handle the requests to increment and decrement the counter.

    Rails.application.routes.draw do
      resources :habits, only: [:show] do
        member do
          post :plus
          post :minus
        end
      end
    end
    

    If you haven't seen the above syntax with member bef

    Building with Turbo Drive 802 words
  • Move Enhancing with Turbo Frames
    Open Enhancing with Turbo Frames

    We've learned that Turbo Drive replaces the <body> element and merges the contents of <head> without reloading the browser. If you open the network tab and follow the redirect, you'll see that Rails renders the entire view for the show action.

    network-tab-drive.png

    It's not that big of a deal in our case, where there's a single component and not too much HTML. However, for most large applications, you'll have a whole lot of other components on the screen, such as a header, a sidebar, some banner image at the top, a comments section, a blog post, etc.

    We don't want to re-render all of these parts on our website every time someone updates the counter. Agreed, Rails is only replacing the body, but still, there can be a lot of HTML to send over the wire. What if instead of sending everything, we could only send the updated counter component?

    **Turbo Frames let us fix this issue by only sending specific HTML that we need to up

    Enhancing with Turbo Frames 828 words
  • Move Finishing Touches with Turbo Streams
    Open Finishing Touches with Turbo Streams

    Let's revisit our view template for the habit counter again. I've also removed the turbo_frame_tag, we won't need it anymore.

    <div class="text-center font-bold text-gray-700" id="habit-name">
      <%= @habit.name %>
    </div>
    
    <div class="mt-3 flex justify-center items-center space-x-5">
      <%= button_to '-', minus_habit_path(@habit), class: 'btn bg-red-300 inline-block shadow-lg' %>
      <div class="text-4xl font-bold"><%= @habit.count %></div>
      <%= button_to '+', plus_habit_path(@habit), class: 'btn bg-green-300 inline-block shadow-lg' %>
    </div>
    
    <div class="mt-3 p-2 flex justify-center space-x-1">
      <% @habit.count.times do %>
        <div class="inline-block border p-1 bg-green-400"></div>
      <% end %>
    </div>
    

    The component is made up of four elements:

    1. The name of the habit

    2. The buttons to update the count

    3. The habit count

    4. The streak markers

    elements.png

    As things stand now, upon clicking th

    Finishing Touches with Turbo Streams 931 words