Rails 6: the missing developer setup guide
Tags: ruby, rails, webpacker, webpack
Published: 2019-11-19 14:53:33

---
title: Rails 6: the missing developer setup guide
published: true
description: Learnings and notes from a JavaScript developer trying out Ruby and Ruby on Rails 6 for the first time.
tags: ruby, rails, webpacker, webpack
cover_image: https://thepracticaldev.s3.amazonaws.com/i/m329bzrdklhi1ys99fq0.jpg
---

👋 Welcome! This post contains everything I learned and did that was not documented as part of my Ruby and Ruby on Rails 6 learning. I am new to the ecosystem and **really looking forward to feedback**, if you have any, drop me a comment here!

Most of the Ruby on Rails tutorials are focused, for good reasons, on using the API. For example the official [Getting Started](https://guides.rubyonrails.org/getting_started.html).

![Rails Getting Started guide](https://thepracticaldev.s3.amazonaws.com/i/cji6yg2xgpfb6uo7viyz.png)

But what happens after a few `rails new blog`, controllers editing and `git push heroku`? Well I wanted to go further, I wanted the *best practices* as for:
- developer setup
- code editor configuration for Ruby and Ruby on Rails
- assets configuration and auto-reloading (Webpacker)
- reproducible builds and safe environments
- a few books and resources to learn more

Those subjects are the ones I struggled the most with because they are the least discussed online: those are **usually learned through experience and usage** of Ruby on Rails.

While learning and deploying Rails applications, I started a README file where I would put all the small traps and bits of code I had to add to solve all the previous subjects.

![This README](https://thepracticaldev.s3.amazonaws.com/i/fhyl6hwmtyjd3ou6p9w6.png)

At some point **the list of notes grew** and I felt I needed to rewrite it in a clean way so that next time I have to start a Rails application, **I already have a reference I can use**.

Making this reference public is a way for me to share my knowledge and help others (you hopefully).

Table of contents:

- [Editor and VS Code setup](#editor-and-vs-code-setup)
- [Webpacker usage](#webpacker-usage)
  * [Using Webpacker for [S]CSS files](#using-webpacker-for-scss-files)
  * [Using Bootstrap 4 with Rail 6](#using-bootstrap-4-with-rail-6)
  * [Auto-reloading of [S]CSS and JavaScript files](#autoreloading-of-scss-and-javascript-files)
- [Automatic testing and desktop notifications](#automatic-testing-and-desktop-notifications)
- [Reproducible environments](#reproducible-environments)
  * [Reproducible environments: Ruby](#reproducible-environments--ruby)
  * [Reproducible environments: Node.js and Yarn](#reproducible-environments--nodejs-and-yarn)
  * [Automatic dependencies updates](#automatic-dependencies-updates)
- [Heroku and double Yarn installs](#heroku-and-double-yarn-installs)
- [Configuration management](#configuration-management)
- [Best resources for learning Ruby and Rails](#best-resources-for-learning-ruby-and-rails)

# Editor and VS Code setup

I extracted this section in its own article, read it here:

{% link https://dev.to/vvo/the-three-extensions-you-need-for-rails-in-vs-code-5h7j %}

# Webpacker usage

*In this part, I speak about [S]CSS because all of this applies to SCSS or CSS files. Webpacker supports [multiple formats](https://github.com/rails/webpacker/blob/master/docs/css.md).*

Webpacker, at first, was confusing for me and here's why:

As of Rails 6, Rails started to bundle and wrap [Webpack](https://webpack.js.org/) inside Rails applications. This is done through [Webpacker](https://github.com/rails/webpacker). What Webpacker provides is a preconfigured Webpack along with view helpers to easily get corresponding generated assets like JavaScript and [S]CSS files.

The state as of November 2019 is that the default Rails application erb template file contains:

**app/views/layout/application.html.erb**
```erb.html
  <%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track": "reload" %>
  <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
```

The second line gets from Webpacker the compiled JavaScript file path generated from the entry point `app/javascript/packs/application.js`.

But the first line, ask the regular Rails asset pipeline (whatever that is today) to generate such a file.

I was confused as to why there is a dual system running on, there might be reasons for that but **let's fix this situation by only using Webpacker to generate our assets**.

## Using Webpacker for [S]CSS files

To use Webpacker for [S]CSS files, for example to use Bootstrap 4 with Rails 6, you need to change the line including your CSS to this:

**app/views/layout/application.html.erb**
```erb
  <%= stylesheet_pack_tag "application", media: "all", "data-turbolinks-track": "reload" %>
```

So that it tells Webpacker to provide us with the right stylesheet asset url for the pack named "application". The name application actually refers to the filename of the main current pack: **app/javascript/packs/application.js**.

You'll notice the change from `stylesheet_link_tag` to `stylesheet_pack_tag`.

Then create the main SCSS file (the name and location of the file actually do not matters):

**app/javascript/src/style.scss**
```scss
@import "~bootstrap/scss/bootstrap"; // if you plan on using bootstrap.
```

And **import it from JavaScript**:

**app/javascript/packs/application.js**:
```js
// [...]
import "../src/style.scss";
```

The stylesheet won't actually be loaded by the JavaScript file, it just tells Webpack to compile it so that we can then require its path in our application template.

## Using Bootstrap 4 with Rail 6

For the `@import "~bootstrap/scss/bootstrap";` bit from the last part to work, you need to install Bootstrap. But not via a Gemfile, via Yarn. Since `~bootstrap` means to Webpack: find this in `node_modules/bootstrap/...`. Add it now:

**in a terminal:**
```sh
yarn add bootstrap
```

For the JavaScript parts of Bootstrap to work, you would have to install the JavaScript dependencies too:

**in a terminal:**
```sh
yarn add jquery popper.js
```

Then require those files in your JavaScript application.

**app/javascript/packs/application.js**:
```js
require("jquery");
require("bootstrap");
```

## Auto-reloading of [S]CSS and JavaScript files

One of the main advantages of Webpack to me is the auto-reloading feature, but it's not activated in Rails 6 by default. Which means that every page load in development will take forever (really). For the auto-reloading to work, you need to use [webpack-dev-server](https://github.com/rails/webpacker/blob/master/docs/webpack-dev-server.md). Fortunately it's already shipped with your new Rails 6 application, all you need to do is launch it alongside your Rails server:

**in a terminal:**
```sh
./bin/webpack-dev-server
```

I like to have a single command to run as for development servers, ideally both `rails server` and `./bin/webpack-dev-server` would be launched in parallel. It seems the easiest and modern way to do so nowadays is to use a `Procfile.dev` and [overmind](https://github.com/DarthSim/overmind).

{% github DarthSim/overmind %}

overmind is basically [foreman](https://github.com/ddollar/foreman/) but done "well". Since I just trust stuff from the internet, I am using it now. Here's what you need to do:

Create **Procfile.dev**:
```Procfile
web: rails server
webpacker:  ./bin/webpack-dev-server
```

Create or update **.env**:
```env
OVERMIND_PROCFILE=Procfile.dev
```

Now instead of using `rails server` or `rails s` locally, just use `overmind`:

**in a terminal:**
```sh
brew install overmind
overmind start
# You can also use overmind s
```

Congrats, your web server now runs at http://localhost:5000 and has fast auto reloading built in.

If you want to [debug your rails server](https://guides.rubyonrails.org/debugging_rails_applications.html), since multiple processes are running via overmind, you need to do this:

```sh
overmind connect web
```

To detach the tmux session opened by overmind and go back to your terminal, hit CTRL+b then d (for **d**etach).

---

Initially I recommended to use the simpler [hivemind](https://github.com/DarthSim/hivemind) but as soon as you need to debug your rails server then hivemind cannot help you there.

**One issue I had** was about Webpacker requesting Yarn integrity checks too often, resulting in slow development environment. Since I know how to ensure my Yarn dependencies are up to date and always the same (see next parts about Reproducible environments), I disabled this feature: https://github.com/rails/webpacker#yarn-integrity.

You can do a lot more with Webpacker, but you won't learn that from the main Rails documentation. To learn more about Webpacker, I recommend [to check out their docs](https://github.com/rails/webpacker/tree/master/docs). I learned everything I needed from them. Especially the [folder structure](https://github.com/rails/webpacker/blob/master/docs/folder-structure.md), [webpack-dev-server](https://github.com/rails/webpacker/blob/master/docs/webpack-dev-server.md) and [CSS](https://github.com/rails/webpacker/blob/master/docs/css.md).

# Automatic testing and desktop notifications

Coming from the JavaScript world, I was used to exceptional JavaScript testing tooling in the name of [Jest](https://jestjs.io/), which is today the standard for testing JavaScript applications (you might be using something else, that's fine). The Ruby and Ruby on Rails testing world is more various. Mostly my needs are: automatic test running, desktop notifications when tests are passing or failing.

As for automatic test running, you can already find a lot of material online, for example [Automating Minitest in Rails 6](https://www.matt17r.com/2019/06/17/im-building-a.html) is a good starting point.

But then, I ~~want~~ need those notifications:
![Example of terminal-notifier](https://thepracticaldev.s3.amazonaws.com/i/e58awyu3om27ns609thu.png)

So that I don't have to leave my editor to check the status of my tests.

Turns out the easiest way to have notifications is to use [terminal-notifier](https://github.com/julienXX/terminal-notifier) along with [terminal-notifier-guard](https://github.com/Codaisseur/terminal-notifier-guard).

All you have to do is to add to your Gemfile, in the `development` and `test` groups:

```txt
gem 'terminal-notifier', '2.0.0'
gem 'terminal-notifier-guard', '1.7.0'
```

And then run `bundle`. Guard will automatically detect the gems and then send you nice notifications.

---

In the first version of this post I advocated for the use of Growl because I could not have terminal-notifier working well but a [commenter on lobste.rs](https://lobste.rs/s/8il3w6/rails_6_missing_developer_setup_guide#c_dpud7p) recommended to try it again and it works.

Growl will also work of course if you're already using it.

# Reproducible environments

Coming from the Node.js and JavaScript world, I developed good habits as for reproducible environments.

What is a reproducible environment? No matter the machine running: Travis CI, Heroku or your macbook it should always run using the same dependencies and platforms/languages versions. At no moment you want Heroku to install dependencies using Yarn 1.1, Ruby 2.4 and Node.js 12.1.0 while your macbook is using Yarn 1.9, Ruby 2.6 and Node.js 12.3.4. And ideally, this should be easy to install, maintain and upgrade all those versions.

This applies to: bundler, Rails, Ruby, Node.js and Yarn. Here's how to do it:

## Reproducible environments: Ruby

We will be using:

1. [rbenv](https://github.com/rbenv/rbenv) to easily install and run different Ruby versions
2. `.ruby-version` to enforce the Ruby version on all platforms
3. `Gemfile` changes to enforce the Ruby version when running Bundler
4. Exact versions for dependencies known as [dependencies pining](https://docs.renovatebot.com/dependency-pinning/)

**1.**, [install rbenv](https://github.com/rbenv/rbenv#installation).

**2.**, create a **.ruby-version** file:

```txt
2.6.5
```

**3.**, indicate in your `Gemfile` the Ruby version for [Bundler](https://bundler.io/) to check against:

```Gemfile
ruby '2.6.5'
```

**4.**, make sure to use exact versions as for your Ruby dependencies in your Gemfile. This means changing lines like:

```txt
gem 'webpacker', '~> 4.0'
```

To:

```
gem 'webpacker', '4.2.0'
```

Luckily we installed a VS Code extension to easily know what is the latest version available of any Ruby dependency, just hover a line in your Gemfile and you'll get this:

![Alt Text](https://thepracticaldev.s3.amazonaws.com/i/nlh3n4vb495s93l0ewps.png)

[Pinning dependencies](https://before-you-ship.18f.gov/infrastructure/pinning-dependencies/) can be a touchy subject. Luckily there's a very good article summarizing the pro and cons of various Gemfile and bundler strategies when coming to specifying versions: <https://thoughtbot.com/blog/a-healthy-bundle>.

## Reproducible environments: Node.js and Yarn

Now that Rails has a dependency on Webpack, it then has a dependency on Node.js and Yarn, surprise! Which means we also need to ensure the versions used for those binaries are specific.

We will be using:

1. An [`.nvmrc`](https://github.com/nvm-sh/nvm#nvmrc) file will specify which Node.js version to install and use. Both Heroku and Travis CI are using it to infer the Node.js version to use.
2. [A Yarn policy](https://yarnpkg.com/lang/en/docs/cli/policies/) will allow us to specify which Yarn version to install and use. This will work on any machine that has Yarn >= 1.13.0 which is one year old, that's safe.
3. The [`engines`](https://docs.npmjs.com/files/package.json#engines) field in your package.json will verify the Yarn and Node.js versions on any Node.js script running (like Webpack from Webpacker)
4. Exact versions for dependencies

To do so, **1.** [install nvm](https://github.com/nvm-sh/nvm#install--update-script).

And create an **.nvmrc** file:
```nvmrc
12.13.1
```

Use the [latest Node.js version](https://nodejs.org/) available when reading this guide.

**2.**, set the Yarn policy **in a terminal**:
```sh
yarn policies set-version 1.19.1
```

This will download Yarn 1.19.1 and create a file `.yarnrc` that will tell any Yarn binary to use Yarn version 1.19.1. **Neat**. Again, use the [latest Yarn version](https://yarnpkg.com/) available when reading this guide.

You can use the latest [LTS](https://nodejs.org/) available.

**3.**, update your **package.json**:
```js
{
  // [...],
  "engines": {
    "node": "12.13.1",
    "yarn": "1.19.1"
  }
}
```

**4.** Pin all your package.json dependencies to use exact versions. To do so, change any line where the version starts like:

```txt
"@rails/webpacker": "^4.2.0",
```

To:

```txt
"@rails/webpacker": "4.2.0",
```

**4.** As for using exact versions of your dependencies in your package.json. This all boils down to updating in your package.json all lines like:

```txt
"@rails/webpacker": "^4.2.0",
```

To:

```txt
"@rails/webpacker": "4.2.0",
```

In the next part we will actually see a tool that can pin dependencies for you.

That's it! Now you have a Node.js and Yarn environment you master.

## Automatic dependencies updates

As we have seen, I always use specific versions for dependencies, this is part of having reproducible environments. You never want to end up in a case where for some reasons an environment or platform is using different versions of your dependencies. This can be a huge waste of time.

Sure lockfiles like Gemfile.lock and yarn.lock do solve a lot of issues, but that's not enough. Not only [there are cases](https://docs.renovatebot.com/dependency-pinning/) where those files might fail. But I also want to know exactly which versions of my direct dependencies I am using at any moment. Both to know which features I have available and which bugs are still here without having to dig into obscure commands to understand what's hidden behind that "~2.x" notation in my package.json or Gemfile.

But then, I still want to upgrade my dependencies from time to time, in a painless way. I recommend checking [Renovate](https://renovate.whitesourcesoftware.com/) which handles JavaScript and Ruby dependencies auto updating. Use it.

# Heroku and double Yarn installs

As for deploying on Heroku, their [Getting started with Rails 6.x](https://devcenter.heroku.com/articles/getting-started-with-rails6) guide is well written, you can follow it.

Now I had a weird behaviour where deploying on Heroku would trigger multiple Yarn installs: one from Heroku when they detect a package.json file and one from Webpacker while bundling the assets. This was annoying and I wanted to separate those tasks into:
1. Install Yarn dependencies
2. Install Ruby dependencies
3. Compile assets

Tasks 1. and 2. are either automatically detected by Heroku or you can also specify them yourself, and their order. To do so you have to define yourself the [buildpacks and buildpacks order](https://devcenter.heroku.com/articles/buildpacks) to use first the Node.js one and then the Ruby one.

Let's do that, **in a terminal**:

```sh
heroku buildpacks:clear
heroku buildpacks:add heroku/nodejs
heroku buildpacks:add heroku/ruby
```

Now we have to disable any Yarn install ran by Webpacker, add to your **Rakefile**:
```rb
Rake::Task['yarn:install'].clear
namespace :yarn do
  desc "Disabling internal yarn install from Rails"
  task :install => [:environment] do
    puts "Disabling internal yarn install from Rails"
  end
end

Rake::Task['webpacker:yarn_install'].clear
namespace :webpacker do
  desc "Disabling internal yarn install from Rails"
  task :yarn_install => [:environment] do
    puts "Disabling internal yarn install from Rails"
  end
end
```

Thanks to [Rebecca Lynn Cremona](https://twitter.com/rebeccacremona) for [digging the issue](https://github.com/harvard-lil/h2o/issues/744).

# Configuration management

I created a dedicated article to speak about credentials, configuration files and environment variables, read it:

{% link https://dev.to/vvo/secrets-environment-variables-config-files-the-ruby-on-rails-case-433f %}

# Best resources for learning Ruby and Rails

I extracted this section in its own article, read it here:

{% link https://dev.to/vvo/modern-resources-for-learning-rails-6-and-ruby-2cbe %}

---

🔚 That's it!

Overall diving into the Rails world feels great from a Node.js background. Hopefully some of the issues mentioned will disappear over time, I will make sure to update this post when that's the case. If you happen to have more information on any of the subjects here, please add a comment or write me at vincent@codeagain.com.

If this guide helped you in any way, share it for others to read it:

{% twitter 1196914255913791488 %}

Thanks for reading.

![Cat reading a book about Rails](https://thepracticaldev.s3.amazonaws.com/i/zzqclhreocqcanozqj6u.gif)