A very simple tutorial about Rails 8 and Bootstrap 5, since starting with Boostrap is given by the framework.

· Ruby  · 5 min read

Rails 8 Bootstrap 5 tutorial

A very simple tutorial about Rails 8 and Bootstrap 5, since starting with Boostrap is given by the framework.

Motivation

Bootstrap used to be the de-facto CSS Frameworks for a long time. Now it’s more Tailwind, but Rails 8 still gives the option to use Bootstrap by default.

1. Prerequisites

I tested on Linux with the tools below :

$> ruby -v
ruby 3.3.0
$> bundle -v
Bundler version 2.5.5
$> npm -v
10.2.4
$> yarn -v
1.22.22

Any upper versions should work.

2. Create an isolated, new Rails 8 app

mkdir myapp && cd myapp
echo "source 'https://rubygems.org'" > Gemfile
echo "gem 'rails', '8.0.0'" >> Gemfile
bundle install
bundle exec rails new . --force --css=bootstrap -j=esbuild

Continue inside bash :

bin/rails db:create
bin/rails db:migrate

3. Is Bootstrap v5 already installed ? a check

In this paragraph, we will not write any code, instead, we will read what is already installed for us.

Some good news : maybe you noticed the --css=bootstrap option above. This means the last Bootstrap version is already installed.

Let’s check where this happens :

package.json

// inside package.json
{
  "name": "app",
  "private": "true",
  // ... other props, the
  "dependencies": {
    "@hotwired/stimulus": "^3.2.2",
    "@hotwired/turbo-rails": "^8.0.12",
    "@popperjs/core": "^2.11.8",
    "autoprefixer": "^10.4.20",
    "bootstrap": "^5.3.3",
    "bootstrap-icons": "^1.11.3",
    "nodemon": "^3.1.7",
    "postcss": "^8.4.49",
    "postcss-cli": "^11.0.0",
    "sass": "^1.81.0"
  },
}

Ok ! Bootstrap 5 and its dependencies is properly installed inside package.json

// inside app/assets/stylesheets/application.bootstrap.scss
@import 'bootstrap/scss/bootstrap';
@import 'bootstrap-icons/font/bootstrap-icons';

Great ! Standard import of bootstrap scss source, this will allow us fine tuning later.

// inside app/javascript/application.js
// Entry point for the build script in your package.json
import '@hotwired/turbo-rails';
import './controllers';
import * as bootstrap from 'bootstrap';

Ok ! JavaScript for Bootstrap is now loaded - even if no initialisation happens so far.

Open app/views/layouts/application.html.erb

<!DOCTYPE html>
<html>
  <head>
    <title><%= content_for(:title) || "Myapp" %></title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="mobile-web-app-capable" content="yes">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= yield :head %>

    <%# Enable PWA manifest for installable apps (make sure to enable in config/routes.rb too!) %>
    <%#= tag.link rel: "manifest", href: pwa_manifest_path(format: :json) %>

    <link rel="icon" href="/icon.png" type="image/png">
    <link rel="icon" href="/icon.svg" type="image/svg+xml">
    <link rel="apple-touch-icon" href="/icon.png">

    <%# Includes all stylesheet files in app/assets/stylesheets %>
    <%= stylesheet_link_tag :app, "data-turbo-track": "reload" %>
    <%= javascript_include_tag "application", "data-turbo-track": "reload", type: "module" %>
    <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
  </head>

  <body>
    <%= yield %>
  </body>
</html>

The interesting lines are javascript_include_tagand stylesheet_link_tag. They allow us to profit from initial SCSS and JS files in each template that inherits from the default layout.

Create bare minimal Bootstrap 5 HTML

Create a controller :

# inside app/controllers/home_controller.rb
class HomeController < ApplicationController
end

Configure a default route :

# inside config/routes.rb
Rails.application.routes.draw do
  get "home/index"
  root to: "home#index"
end

Now create a view tailored for Bootstrap 5 : just copy/paste the code below into app/views/home/index.html.erb

<!-- inside app/views/home/index.html.erb -->
<h1>Welcome, this is the home page</h1>

<button
  type="button"
  class="btn btn-lg btn-danger"
  data-bs-toggle="popover"
  title="Popover title"
  data-bs-content="Amazing content, right ?"
>
  Click to toggle popover
</button>

This HTML should show a popover when clicking the red button, only if

  • Bootstrap CSS is properly configured,
  • Bootstrap JS is loaded and initialized.

Great ! This bare minimalistic example will ensure everything works properly.

Bootstrap 5, Rails 8, locally : let’s start !

$/myapp> ./bin/dev

17:24:24 web.1 | started with pid 26889
17:24:24 js.1 | started with pid 26890
17:24:24 css.1 | started with pid 26891
17:24:24 css.1 | yarn run v1.22.10
17:24:24 js.1 | yarn run v1.22.10
17:24:24 css.1 | $ sass ./app/assets/stylesheets/application.bootstrap.scss ./app/assets/builds/application.css --no-source-map --load-path=node_modules --watch
17:24:24 js.1 | $ esbuild app/javascript/*.* --bundle --sourcemap --outdir=app/assets/builds --watch
17:24:25 js.1 | [watch] build finished, watching for changes...
17:24:25 css.1 | Sass is watching for changes. Press Ctrl-C to stop.
17:24:25 css.1 |
17:24:26 web.1 | => Booting Puma
17:24:26 web.1 | => Rails 7.0.0 application starting in development
17:24:26 web.1 | => Run `bin/rails server --help` for more startup options
17:24:26 web.1 | Puma starting in single mode...
17:24:26 web.1 | * Puma version: 5.5.2 (ruby 3.0.0-p0) ("Zawgyi")
17:24:26 web.1 | * Min threads: 5
17:24:26 web.1 | * Max threads: 5
17:24:26 web.1 | * Environment: development
17:24:26 web.1 | * PID: 26889
17:24:26 web.1 | * Listening on http://127.0.0.1:3000
17:24:26 web.1 | * Listening on http://[::1]:3000
17:24:26 web.1 | Use Ctrl-C to stop

Great ! the console indicates that we should go to localhost:3000 to see what is happening. Let’s go :

localhost
localhost

Try to click the button. Nothing happens.

Adding custom Bootstrap-based JavaScript into Rails

Let’s follow the Bootstrap docs about popovers here :

And inject it into Rails

// Inside app/javascript/application.js  
import "@hotwired/turbo-rails"  
import "./controllers"  
import * as bootstrap from "bootstrap"  
  
let popoverTriggerList = [].slice.call(document.querySelectorAll('[data-bs-toggle="popover"]'))  
let popoverList = popoverTriggerList.map(function (popoverTriggerEl) {  
  return new bootstrap.Popover(popoverTriggerEl)  
})  

Now reload your browser, and click the big red button

localhost
localhost

Great ! it works

Add custom SCSS

// inside app/assets/stylesheets/application.bootstrap.scss  
$h1-font-size: 1rem; // this line was added  
@import 'bootstrap/scss/bootstrap';  

Reload your browser

A smaller h1 title
A smaller h1 title

Summary

I tried to write the most possible Rails 8 and Bootstrap 5 tutorial, hope it helped.

Enjoy!

Share:
Back to Blog

Related Posts

View All Posts »
How to create tons of Rails apps

How to create tons of Rails apps

Yes, I already now about the rails new command. But what if you want better defaults, like an existing controller, an existing view, or another way to to launch the Procfile?

Rails new options

Rails new options

Let's see the official way to create Rails application, as well as the minimalistic option.

Rails active support

Rails active support

A review of the benefits of Rails ActiveSupport, through an interview of a Rails teacher.