Integrating Bootstrap 4 into Rails 6

…and how to use a theme

To install Bootstrap 4 and a theme, we are going to be adding some packages, updating some configuration and adding a few additional gems/libraries to make life developing easier. This is going to assume you have already started an app with rails new app_name

Note: This tutorial is an excerpt from a chapter in my upcoming book Build A SaaS App in Rails 6. The book guides you from humble beginnings by deploying an app to production. The book is now in pre-sale, and you can grab a free chapter right now!

The first thing to do is to add another version manager! Since we are using Yarn/NPM/Node, it is a good idea to manage the version of Node a particular application or directory will be using. To do so, we will use NVM, and you can install the NVM with the following line. If you are one to look at the github repo or the install scripts, [you can here](https://github.com/nvm-sh/nvm).

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash

That line grabs the install script from Github and runs it as Bash.

Now the current LTS (Long Term Stable) version of Node is version 10. LTS versions in the OSS (Open Source) communities is the version in which you can rely on long term stability. To install Node use the following command:

nvm install 10

This line installs the latest updated version of version 10. Meaning, as small updates and bugfixes are released to the version 10 pipeline, they bump the version numbers under 10 (i.e., 10.3.4 -> 10.3.5). Once installed, you can tell your terminal window/pane to use node 10 with the following command:

nvm use 10

When you created your new app, Rails should have made sure brewand yarnwere added. Thus, you should now be able to install AdminLTE, Bootstrap, and a few other dependencies needed to get AdminLTE up and running in your application.

First, to install a version of AdminLTE that is compatible with Bootstrap 4, we will need to install through Yarn on a specific Github branch.

yarn add https://github.com/ColorlibHQ/AdminLTE#v3-dev

This command is saying, install AdminLTE to the remote Github repo `ColorlibHQ/AdminLTE` and use the `v3-dev`. Next, we also install the packages for Bootstrap, jQuery and Popper.js to make sure they are available to the Rails application:

yarn add bootstrap jquery popper.js

That should take care of making sure all of the packages we need for the theme are there, but it seems as though Rails does not entirely install everything needed for Webpacker to get up and running. To remedy this issue, let’s run the Webpacker install.

rails webpacker:install

Alright, we are getting close to being done with setup! However, we should digress a bit in regards to Webpacker.

Webpacker is the Ruby (Rails mostly) wrapper gem around the Javascript tool, Webpack. Webpack is a tool that allows you to pre-process, bundle and use ES6 like syntax inside Javascript. Webpacker then takes all of those features and starts to merge the ES6 Javascript world with the Asset pipeline for CSS and other more static assets.

Webpacker introduces a concept of “packs” which are ES6 syntax Javascript files that you can then include in any template with a pack_taghelper. Think of packs as entry points of javascript files into specific spots in a Rails app.

The most basic pattern is the /app/javascript/application.jspack file, which is then included in the applications’ layout file by default.

As your application grows, using packs to specify specific libraries and functionality within specific templates or sections of your application helps make sure your Javascript stays modular and compartmentalized.

Running A Webpack Dev Server

If you have used Heroku or other hosting vendors you may see reference to Procfile. The simplest definition of a Procfile is that it allows you to specify a list of different process types and let another system(Heroku, Foreman gem, etc.) handle startup and shutdown. Allow all of that to be dealt with one line and one terminal session/tab/pane.

When developing locally, the easiest step to take is to use the gem Foreman. To add this gem, add it to the development group in your Gemfileand bundle install:

...
group :development do
gem 'foreman'
...

Once added, you can add your Procfile to the root of app’s folder structure. Meaning the same level as your Gemfile.

web: bundle exec puma -t 5:5 -p ${PORT:-3000} -e ${RACK_ENV:-development}

You may notice that instead of rails s, you see bundle exec puma. This change is due to how you would want to run Puma directly in most environments.

If you were to start your environment with Foreman and this procfile, you would use the following on the command line:

foreman start

That command starts up a process for each line in your Procfile. Thus, in this case, a process for Puma, to run the Rails server. However, if you visit your instance of the app, first you may notice it is now at http://localhost:5000, and it is also not outputting development logs.

So, how can we make development use rails sto keep the fancy logs? We can create a secondary Procfile.devthat is utilized just for development.

web: bin/rails s -p ${PORT:-3000}
webpacker: ./bin/webpack-dev-server

What is `webpack-dev-server`?

Very simply, it is a server that runs in the background that allows you to develop your Javascript, hand automatic reloads and making sure packs are served to you your development Rails server.

To get this Procfile running instead, you simply just need to add a field to your command line syntax:

PORT=3000 foreman start -f Procfile.dev

Ok, we’re getting so close to getting everything up and running. We’re down to adding just a few additions to the Webpack javascript configuration.

// config/webpack/environment.js
const { environment } = require('@rails/webpacker')
const webpack = require('webpack')
// Add an additional plugin of your choosing : ProvidePlugin
environment.plugins.prepend('Provide', new webpack.ProvidePlugin({
$: 'jquery',
JQuery: 'jquery',
jquery: 'jquery',
'window.Tether': "tether",
Popper: ['popper.js', 'default'], // for Bootstrap 4
})
)
module.exports = environment

One of the additions are the 8 lines of plugin code that is used to make sure jQuery, Popper.js and Tether are available throughout the bundled javascript.

When adding Javascript to a Rails application, there are javascript libraries, setup or variables you want throughout the application. In the world of Rails 6 and Webpacker, these items go in the Application Pack, located at /app/javascript/application.js. The good news is that this file a bit of content is created when you used the Rails command to create a new Rails app. Let’s go over the additions to get AdminLTE’s needs fulfilled.

/ This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.
require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")
var jQuery = require("jquery")
// import jQuery from "jquery";
global.$ = global.jQuery = jQuery;
window.$ = window.jQuery = jQuery;
require('bootstrap');
require('admin-lte')
// Uncomment to copy all static images under ../images to the output folder and reference
// them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>)
// or the `imagePath` JavaScript helper below.
//
// const images = require.context('../images', true)
// const imagePath = (name) => images(name, true)

The commented code and the first four lines of `require`s are added by default. These are libraries or packages that Rails needs for most applications. The new lines are adding jQuery and variables that other packages or libraries may expect to exist. Lastly, `bootstrap` and `admin-lte` are required to make available to the entire Rails application.

Why `require` and not `import`?

If you have done any recent javascript development, you may question why we are using `require` and not `import`. The answer here is rather simple. Based on the packages we are using and adding in, they expect other’s to have loaded first. Most specifically, admin-lteexpects the global variable jQueryto exist when it loads. Using requireguarantees code is executed in the order of the file, whereas importusually is pre-processed and executed out of order.

Lastly, we need to add some imports to the bottom of the automatically created Application Stylesheet. If you have done any Rails development in the last few years, you may have interacted with the Asset Pipeline, which is the way Rails handled the inclusion of javascript, stylesheets and any other static assets.

app/assets/stylesheets/application.css


*
* This is a manifest file that'll be compiled into application.css, which will include all the files
* listed below.
*
* Any CSS and SCSS file within this directory, lib/assets/stylesheets, or any plugin's
* vendor/assets/stylesheets directory can be referenced here using a relative path.
*
* You're free to add application-wide styles to this file and they'll appear at the bottom of the
* compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
* files in this directory. Styles in this file should be added after the last require_* statement.
* It is generally better to create a new file per style scope.
*
*= require_tree .
*= require_self
*/
@import url("https://fonts.googleapis.com/css?family=Source+Sans+Pro:300,400,600,700&lang=en");
@import 'bootstrap';
@import 'admin-lte/dist/css/adminlte';

In CSS, you can include other stylesheets or fonts by using the @import syntax. In this stylesheet above, we are adding a font from Google Fonts that are referenced in AdminLTE’s stylesheets. Next, we include stylesheets for Bootstrap, AdminLTE and Font Awesome (the icons referenced by AdminLTE).

In the following section, we are going to add some Controllers and Templates to added the necessary markup to structure the application.

Before we begin implementing the layout, we need to apply a route and controller to bypass the default welcome page. We also will be using this controller in the application as we go along.

Let’s also pause to mention that Rails comes with built-in command line generators to generate controllers, models, mailers. As well as generating database migration file or even generating a scaffold of all of those combined. In our case, let’s focus on the controller generator. The general format for this generator is:

rails generate controller Activity mine feed

It created a controller with empty methods for the actions we included in the command line. It created template files, test files, and other auxiliary files.

Let’s make one quick edit to the route file to define a default route, adding “root to: ‘activity#mine’” to the bottom of the route file, as follows:

Rails.application.routes.draw do
get ‘activity/mine’
  get ‘activity/feed’
  root to: ‘activity#mine’
end

As we had set up the theme package, application javascript file and application stylesheet file earlier in the chapter, we can get into writing the markup needed to implement this theme rather quickly.

First, we can modify the main layout file to include the necessary elements and classes to wrap the content that will be provided by routed templates.

app/views/layouts/application.html.erb




Some App
<%= csrf_meta_tags %>
<%= csp_meta_tag %>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
<%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
<-- Make your own FontAwesome Kit on their site -->


<%= render partial: "layouts/header" %>
<%= render partial: "layouts/sidebar" %>

<%= yield %>

<%= render partial: "layouts/footer" %>


The details of this file are not all pertinent to the addition of the Bootstrap theme, so we’ll only touch on those that matter. First, a class is added to the body element, “body class=”sidebar-mini””. Next, “

” and “

” are added as wrapping elements to the first the page and then the inner content. You may notice there is some included Ruby code in there as well. Those `render partial: ` calls allow us to add markup from other template files, in that position. In this case, it adds various larger parts of the application template such as the header, sidebar or footer. Plus, it keeps the layout to only the most necessary foundational elements to build the page structure. Then, “<%= yield %>” which is the Rails’ template method for adding the template from the controller and action called.

Since we are using partial templates, we go ahead and create the header file next.

One thing to note here is the use of the underscore in the template file’s name. In Rails, partial template files are designated with an underscore at the beginning of the file name. What are partials? Partials are simply a way to break down templates into smaller chunks. This approach comes into far greater play in situations such as looping over a collection of items. There, you would make the template chunk to display item information a partial. For example, the header template is titled _header.erb.

app/views/layout/_header.erb











This template contains the structure to have the app title/logo, dropdowns and any additional links you may need for navigation. To get the app template structure setup, we can leave in some of the demo data and elements to show how the dropdowns would look and work.

The next partial to create is the _sidebartemplate:

app/views/layouts/_sidebar.erb







As you see, the sidebar partial is a bit smaller and more straightforward. It contains a little bit of user information and links to other parts of the application that we change later.

The last major piece of the layout is the footer. It is simple, and it is short. Again, it is another partial. Here is the ERB markup:

app/views/layouts/_foooter.erb


Copyright © 2019 Your Stuff.
All rights reserved.

Now, to have all of this show up on a page, you can edit the root controller action’s template to use the theme’s div classes

app/views/activity/mine.html.erb





Some Page











Stuff





That’s about it to get set up with Bootstrap 4 and Rails 6.


Integrating Bootstrap 4 into Rails 6 was originally published in Hacker Noon on Medium, where people are continuing the conversation by highlighting and responding to this story.