loading...
Cover image for Rails 6: the missing developer setup guide

Rails 6: the missing developer setup guide

vvo profile image Vincent Voyer Originally published at dev.to Updated on ・11 min read

👋 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.

Rails Getting Started guide

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

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

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

Webpacker usage

In this part, I speak about [S]CSS because all of this applies to SCSS or CSS files. Webpacker supports multiple formats.

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

As of Rails 6, Rails started to bundle and wrap Webpack inside Rails applications. This is done through 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

  <%= stylesheet_link_tag "application", media: "all", "data-turbolinks-track": "reload" %>
  <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
Enter fullscreen mode Exit fullscreen mode

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

  <%= stylesheet_pack_tag "application", media: "all", "data-turbolinks-track": "reload" %>
Enter fullscreen mode Exit fullscreen mode

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

@import "~bootstrap/scss/bootstrap"; // if you plan on using bootstrap.
Enter fullscreen mode Exit fullscreen mode

And import it from JavaScript:

app/javascript/packs/application.js:

// [...]
import "../src/style.scss";
Enter fullscreen mode Exit fullscreen mode

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:

yarn add bootstrap
Enter fullscreen mode Exit fullscreen mode

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

in a terminal:

yarn add jquery popper.js
Enter fullscreen mode Exit fullscreen mode

Then require those files in your JavaScript application.

app/javascript/packs/application.js:

require("jquery");
require("bootstrap");
Enter fullscreen mode Exit fullscreen mode

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. 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:

./bin/webpack-dev-server
Enter fullscreen mode Exit fullscreen mode

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.

GitHub logo DarthSim / overmind

Process manager for Procfile-based applications and tmux

Overmind

Release Build Status

Overmind is a process manager for Procfile-based applications and tmux. With Overmind, you can easily run several processes from your Procfile in a single terminal.

Procfile is a simple format to specify types of processes your application provides (such as web application server, background queue process, front-end builder) and commands to run those processes. It can significantly simplify process management for developers and is used by popular hosting platforms, such as Heroku and Deis. You can learn more about the Procfile format here.

There are some good Procfile-based process management tools, including foreman by David Dollar, which started it all. The problem with most of those tools is that processes you want to manage start to think they are logging their output into a file, and that can lead to all sorts of problems: severe lagging, losing or breaking colored output. Tools can also add vanity information…

overmind is basically 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:

web: rails server
webpacker:  ./bin/webpack-dev-server
Enter fullscreen mode Exit fullscreen mode

Create or update .env:

OVERMIND_PROCFILE=Procfile.dev
Enter fullscreen mode Exit fullscreen mode

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

in a terminal:

brew install overmind
overmind start
# You can also use overmind s
Enter fullscreen mode Exit fullscreen mode

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, since multiple processes are running via overmind, you need to do this:

overmind connect web
Enter fullscreen mode Exit fullscreen mode

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


Initially I recommended to use the simpler 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. I learned everything I needed from them. Especially the folder structure, webpack-dev-server and CSS.

Automatic testing and desktop notifications

Coming from the JavaScript world, I was used to exceptional JavaScript testing tooling in the name of Jest, 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 is a good starting point.

But then, I want need those notifications:
Example of terminal-notifier

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 along with terminal-notifier-guard.

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

gem 'terminal-notifier', '2.0.0'
gem 'terminal-notifier-guard', '1.7.0'
Enter fullscreen mode Exit fullscreen mode

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 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 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

1., install rbenv.

2., create a .ruby-version file:

2.6.5
Enter fullscreen mode Exit fullscreen mode

3., indicate in your Gemfile the Ruby version for Bundler to check against:

ruby '2.6.5'
Enter fullscreen mode Exit fullscreen mode

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

gem 'webpacker', '~> 4.0'
Enter fullscreen mode Exit fullscreen mode

To:

gem 'webpacker', '4.2.0'
Enter fullscreen mode Exit fullscreen mode

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

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 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 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 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.

And create an .nvmrc file:

12.13.1
Enter fullscreen mode Exit fullscreen mode

Use the latest Node.js version available when reading this guide.

2., set the Yarn policy in a terminal:

yarn policies set-version 1.19.1
Enter fullscreen mode Exit fullscreen mode

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 available when reading this guide.

You can use the latest LTS available.

3., update your package.json:

{
  // [...],
  "engines": {
    "node": "12.13.1",
    "yarn": "1.19.1"
  }
}
Enter fullscreen mode Exit fullscreen mode

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

"@rails/webpacker": "^4.2.0",
Enter fullscreen mode Exit fullscreen mode

To:

"@rails/webpacker": "4.2.0",
Enter fullscreen mode Exit fullscreen mode

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:

"@rails/webpacker": "^4.2.0",
Enter fullscreen mode Exit fullscreen mode

To:

"@rails/webpacker": "4.2.0",
Enter fullscreen mode Exit fullscreen mode

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 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 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 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 to use first the Node.js one and then the Ruby one.

Let's do that, in a terminal:

heroku buildpacks:clear
heroku buildpacks:add heroku/nodejs
heroku buildpacks:add heroku/ruby
Enter fullscreen mode Exit fullscreen mode

Now we have to disable any Yarn install ran by Webpacker, add to your Rakefile:

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
Enter fullscreen mode Exit fullscreen mode

Thanks to Rebecca Lynn Cremona for digging the issue.

Configuration management

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

Best resources for learning Ruby and Rails

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


🔚 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:

Thanks for reading.

Cat reading a book about Rails

Discussion

pic
Editor guide
Collapse
ivanshamatov profile image
Ivan Shamatov

Nice article, thanks. In my notes I also have:

  • circleci/travisci/gitlabci files,
  • docker&compose,
  • github/lab templates for PRs, issues,
  • rubocop, simplecov and
  • a list of prefered gems for
    • decorators,
    • serializers,
    • operations,
    • dry-package
Collapse
ivanshamatov profile image
Ivan Shamatov

lefthook or any other precommit config would be nice to have

Collapse
hachi8833 profile image
hachi8833

I'd like to translate the article dev.to/vvo/a-rails-6-setup-guide-f... into Japanese and publish on our tech blog techracho.bpsinc.jp/ for sharing it. Is it OK for you?

I make sure to indicate the link to original, title, author name in the case.

Best regards,

Collapse
vvo profile image
Vincent Voyer Author

Yes, no problem

Collapse
hachi8833 profile image
hachi8833

Published the JP translation techracho.bpsinc.jp/hachi8833/2019...
Thank you very much for your kindness! 😂

Thread Thread
vvo profile image
Collapse
pandelis profile image
Pandelis

My solution for notifications in my scripts is to use the bell sound and apple script.

# Notify that user input is needed
   tput bel
   osascript -e 'display notification "Please fill in your CA information" with title "Infrastructure Setup"'
Collapse
wdiechmann profile image
Walther Diechmann

Ohh do we need this kind of best practices build-ups! Thx for sharing!

You might consider overmind as a sort of "icing on the cake" though ;)

Read about it here: evilmartians.com/chronicles/introd...

Collapse
vvo profile image
Vincent Voyer Author

Indeed I saw overmind but since I yet did not know why I would need it vs the simpler version of hivemind then I went for the simpler version. Maybe later of if you already have killer features we would need maybe? Thanks!

Collapse
ryanwjackson profile image
Ryan

I found in order to get jQuery $ to be defined properly, I had to follow step (3) here: botreetechnologies.com/blog/introd...

Otherwise, everything here worked.

Collapse
vvo profile image
Vincent Voyer Author

I found in order to get jQuery $ to be defined properly
Do you mean for window.$ to be available globally? If so yes that's the way to do it as seen here: webpack.js.org/plugins/provide-plu...

But I prefer to require it whenever I need it rather than relying on a global variable. Still, thanks for heads up!

Collapse
mpressen profile image
Maximilien Pressensé

Hey, super interesting stuff.
Thanks a lot, especially for the webpack and overmind part.

I had an extra issue with webpack handling stylesheets :
delivering images from the asset pipeline in [s]css needs a tiny bit of extra configuration : stackoverflow.com/a/57175231/8131629

Cheers from Vigneux de Bretagne :)

Collapse
vvo profile image
Vincent Voyer Author

Nice, I yet have to use that but once I do Ill make sure to edit this post or create a new one focused on webpacker + Rails.

Thanks for reading and adding your comment! Cheers from Rezé, France :D

Collapse
rpruizc profile image
Rodolfo Ruiz

Nice article. The renovate tip along with hivemind and the pointer to learn more about what webpack can do with rails are huge.
A very small typo in the "Reproducible environments: Node.js and Yarn" section. Step 1 says "12.13.1" while 3 is "12.13.0" I know it doesn't break anything but just to avoid minor confusions to the reader.

Collapse
vvo profile image
Vincent Voyer Author

Thanks a lot, updated!

Collapse
vvo profile image
Vincent Voyer Author

Updated on Nov 26, 2019:

  • switch from Growl to terminal-notifier
  • switch from hivemind to overmind (to allow debugging rails server)
  • add notes about dependencies pinning and link to article thoughtbot.com/blog/a-healthy-bundle
  • add note about rubocop and rufo
Collapse
robcarruthers profile image
robcarruthers

Great work Vincent, really helpful.

Thanks for your encouragement towards the Webpacker docs too... I'm pleasantly surprised.

Collapse
schneems profile image
Schneems

Hi! Heroku Ruby buildpack maintainer, you shouldn’t need the extra nodejs buildpack, the Ruby buildpack installs yarn and node for you, then you don’t also need the extra code clearing the rake tasks.

Collapse
vvo profile image
Vincent Voyer Author

Hi there! Thanks for jumping in, I tested again and here's the result:

  • used official rails 6 getting started here: devcenter.heroku.com/articles/gett... (if you follow it, you'll also see there are some minors issues like: rails new already creates a GIT repo, ruby version is already specified)
  • when building, the output from Heroku website is not the one I am getting: screenshot

As you can see, there are two yarn installs being done somehow vs one in your tutorial. But again, I just used the exact same commands (Rails 6.0.1). It seems others are also wondering what's happening: github.com/harvard-lil/h2o/issues/744 and github.com/rails/webpacker/issues/405

I bet this is not an issue of the Ruby buildpack but more an issue of Rails. There's also maybe no issue but if so then I would love for you to explain to me what's going on maybe.

From my point of view it's easier for Rails to leave the whole "package.json dependencies installation" to the users rather than trying to be smart about it.

Collapse
ben profile image
Ben Halpern

Fabulous guide

Collapse
vvo profile image
Vincent Voyer Author

Thanks! I made some minor edits right now.

First experience contributing to dev.to. It was 11am today and I thought "I really really need to publish/write about Rails setup I have". Two seconds later I was on dev.to, congrats :)

Collapse
mipmip profile image
Pim Snel

Nice article. I think: app/views/layout/application.erb.html should be app/views/layout/application.html.erb

Collapse
vvo profile image
Vincent Voyer Author

Thanks, just updated a bunch of places in the article that contained this typo.

Collapse
mipmip profile image
Pim Snel

Shouldn't the overmind command be: overmind start -D?

Collapse
vvo profile image
Vincent Voyer Author

Indeed I fixed it now in the article, but I do not use -D myself, I like to have the process attached to my session but usage depends I guess. What's you preference and why? Thanks!

Collapse
yaro_the_slav profile image
Collapse
functionalstoic profile image
JasonSooter

Nice work! Created just enough curiosity to actually try out rails!