2020-10-07 • Updated 2021-01-18
This is a brief tutorial detailing how I've set up new Rails 6 apps with PostgreSQL, Tailwind CSS, and Stimulus.
Update: I wrote this post back in October, and for whatever reason I never published it. I'm publishing it now, backdated to emphasize that I make no guarantees that everything in here is up-to-date. I will say, however, that with the Hotwire announcement and Tailwind 2.0, a setup like this has become even more attractive.
This post assumes you have Ruby, Rails, and PostgreSQL installed on a Unix-based operating system (like macOS or Linux). These instructions were created using Ruby 2.7.1, Rails 6.0.3.2, and Postgres 12.3, but will probably work fine on other setups as long as you're on Rails 6 or greater.
We'll be creating a new rails app called myapp
. Replace myapp
with the
desired name of your app throughout this post.
Create a new Rails project, using Postgres as the database:
rails new myapp -d=postgresql
cd myapp
Add a .gitignore
file in the project's root directory. Here's a good one:
# Ignore bundler config.
/.bundle
# Ignore all logfiles and tempfiles.
/log/*
/tmp/*
!/log/.keep
!/tmp/.keep
# Ignore pidfiles, but keep the directory.
/tmp/pids/*
!/tmp/pids/
!/tmp/pids/.keep
# Ignore uploaded files in development.
/storage/*
!/storage/.keep
/public/assets
.byebug_history
# Ignore master key for decrypting credentials and more.
/config/master.key
/public/packs
/public/packs-test
/node_modules
/yarn-error.log
yarn-debug.log*
.yarn-integrity
I also like to ignore all files generated by my IDE, RubyMine, so I add this line:
# Ignore Jetbrains files
**/.idea/
You might want to include your IDE's files or include just some of them. Or maybe you don't use an IDE. Adapt accordingly.
It's at this point I add a readme, changelog, and license file to the project root. How you do this and in what format is up to you. I use markdown files for all three, and base my changelog on the format detailed at Keep a Changelog.
Code linters are a point of contention in the development community. My preference is to use the heavily-tuned-down Rubocop config used in the official Rails repo. I literally just dump this file as-is into my project root. You may have to set up Rubocop manually depending on your setup. RubyMine handles that for me.
If you decide to use Rubocop, you'll want to add the gems to your Gemfile
.
For all Rubocop setups, you'll need the rubocop
gem. If you're using the
Rails project's config I mentioned above, you'll need two additional gems.
Here's what I have in my Gemfile
, under the development
group:
group :development do
gem "rubocop", ">= 0.47", require: false
gem "rubocop-performance", require: false
gem "rubocop-rails", require: false
# There's some other stuff in here by default, too.
end
Time to install all your gems if you haven't already. Make sure you're using rbenv or an equivalent.
bin/bundle install
Before we hook things up to Rails, make sure Postgres is ready to go. You
should create a role named myapp
with a password and the CREATEDB
privilege. Instructions on creating a role like this are widely available on
the internet. You can do it through the shell or via a program like DataGrip
or pgAdmin. Make sure to note down the password, you'll need it.
Once the role is created, add its name and password to config/database.yml
.
For example, if you set the password to beanburrito
, your file would contain
something like this:
# In config/database.yml
development:
<<: *default
database: myapp_development
username: myapp
password: beanburrito
Now you should be able to run the database setup and initial migration:
bin/rails db:setup db:migrate
At the time of this writing, by default, Rails uses webpack for JavaScript and the asset pipeline for CSS/SCSS/Sass. I know some people like to run both their JavaScript and CSS through webpack. The projects I've worked on recently take that route. I pass no judgement here, but if you want to do that, you'll need to rejigger your files a bit, as follows.
Note: For the purposes of this post, I'm writing these instructions for a pure CSS project. You can use a SCSS or Sass with Tailwind just fine, though. For info on that, check out this section of the Tailwind docs.
To run your CSS through webpack, move the stylesheets directory at
app/assets/stylesheets
to app/javascript/stylesheets
. Some people like to
rename the javascript
directory at this point since it now contains CSS as
well, but I leave that up to you.
You'll also want to open app/views/layouts/application.html.erb
and change
stylesheet_link_tag
to stylesheet_pack_tag
.
Now you can create a file at app/javascript/stylesheets/application.css
to be
the main entrypoint for your CSS. Then, import it in your webpack entrypoint:
// In app/javascript/packs/application.js
import "../stylesheets/application.css"
Next up is Tailwind installation. I've been using Tailwind for a year or two, and I really dig it. The utility-first structure seems pretty good, and it's easily to customize and extend beyond the built-in utilities.
Anyway, install Tailwind via yarn:
yarn add tailwindcss
After that's done, you'll want to create a config file in the project root
named tailwind.config.js
. Here's a skeletal config you can use:
// tailwind.config.js
module.exports = {
purge: [],
theme: {
extend: {},
},
variants: {},
plugins: [],
}
Import the core tailwind styles in your application.css
file:
@import "tailwindcss/base";
@import "tailwindcss/components";
/* If you add other imports, they should go here. */
@import "tailwindcss/utilities";
Finally, update your PostCSS config in the project root. You'll need to include
tailwindcss
and autoprefixer
, so your file might end up looking like this:
// In postcss.config.js
module.exports = {
plugins: [
require('tailwindcss'),
require('autoprefixer'),
require('postcss-import'),
require('postcss-flexbugs-fixes'),
require('postcss-preset-env')({
autoprefixer: {
flexbox: 'no-2009'
},
stage: 3
})
]
}
Eventually, you'll want to set up PurgeCSS for use in production, but I
don't want to spend too much time on that here. Make sure to read that page
so you understand what's happening, and then you'll want to add a purge
section to your Tailwind config that will look something like this:
// In tailwind.config.js
module.exports = {
purge: {
content: ["./app/views/**/*.html.erb", "./app/views/**/*.js.erb"],
},
// The rest of your config goes here.
}
I highly recommend that you read that page about PurgeCSS, because it has important information on how you need to write your views so the purge will work properly. Without purge, you will end up with oversized asset files.
Let's get Stimulus working. First, install it with yarn:
yarn add stimulus
Then all you need to do is load Stimulus and your controllers:
// In app/javascript/packs/application.js
import { Application } from "stimulus";
import { definitionsFromContext } from "stimulus/webpack-helpers";
const application = Application.start();
const context = require.context("../controllers", true, /\.js$/);
application.load(definitionsFromContext(context));
That configuration will cause your app to look for Stimulus controllers in
app/javascript/controllers/
.
At this point, you should be good to go. Start up the webpack dev server from your apps's root directory so your app will hot reload when any changes are made to your CSS or JS:
./bin/webpack-dev-server
Then you can start up the Rails server and get hacking!
rails s
Questions, comments, or tips for me? See a mistake in this post? Send me an email.