DEV Community

Konnor Rogers
Konnor Rogers

Posted on • Edited on • Originally published at blog.konnor.site

Getting Started with Rails 6

Getting Started with Rails 6 and Docker

This post is best viewed on my Blog site.

https://paramagicdev.github.io/my-blog/rails/getting-started-with-rails-6/

Purpose

The purpose of this is to have a reusable source for setting up a Rails
6 project.

I will be using the Getting Started with Rails Guide to setup a
new Rails projects.

Initially I used Docker Quickstart with Compose and Rails guide but quickly realized I
had other needs for Rails 6. My docker setup is the result of multiple
resources.

I will also be using Docker just to provide a consistent development
environment. Docker is not required, I used it simply to be able to
provide a reproducible environment.

Source code can be found here:

https://github.com/ParamagicDev/getting-started-with-rails-6

Deployed application can be found here:

https://getting-started-with-rails-6.herokuapp.com/

Table Of Contents

Prerequisites

Make sure to install both Docker and Docker Compose prior to starting
this tutorial.

To verify run the following:

docker -v
# Docker version 19.03.8

docker-compose -v
# docker-compose version 1.25.0
Enter fullscreen mode Exit fullscreen mode

Main Technologies

  • Ruby 2.5.8
  • Rails 6.0.2
  • PostgresQL 11.6

Getting Started

If you don't want any explanations, skip to the I know what I'm doing
section of this post.

Alright first lets create our directory where we want the Rails app. I
named mine getting-started-with-rails-6

mkdir getting-started-with-rails-6
cd getting-started-with-rails-6
Enter fullscreen mode Exit fullscreen mode

Adding a Dockerfile

The next step is to create our Dockerfile.
The below Dockerfile is modified from the Docker Quickstart
Rails

# Dockerfile

# Pre setup stuff
FROM ruby:2.5.8 as builder

# Add Yarn to the repository
RUN curl https://deb.nodesource.com/setup_12.x | bash     && curl https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -     && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list

# Install system dependencies & clean them up
RUN apt-get update -qq && apt-get install -y \
    postgresql-client build-essential yarn nodejs \
    libnotify-dev && \
    rm -rf /var/lib/apt/lists/*

# This is where we build the rails app
FROM builder as rails-app

# Allow access to port 3000
EXPOSE 3000
EXPOSE 3035

# This is to fix an issue on Linux with permissions issues
ARG USER_ID=1000
ARG GROUP_ID=1000
ARG APP_DIR=/home/user/myapp

# Create a non-root user
RUN groupadd --gid $GROUP_ID user
RUN useradd --no-log-init --uid $USER_ID --gid $GROUP_ID user --create-home

# Remove existing running server
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh

# Permissions crap
RUN mkdir -p $APP_DIR
RUN chown -R $USER_ID:$GROUP_ID $APP_DIR


# Define the user running the container
USER $USER_ID:$GROUP_ID

WORKDIR $APP_DIR

# Install rails related dependencies
COPY --chown=$USER_ID:$GROUP_ID Gemfile* $APP_DIR/

# For webpacker / node_modules
COPY --chown=$USER_ID:$GROUP_ID package.json $APP_DIR
COPY --chown=$USER_ID:$GROUP_ID yarn.lock $APP_DIR

RUN bundle install

# Copy over all files
COPY --chown=$USER_ID:$GROUP_ID . .

RUN yarn install --check-files


ENTRYPOINT ["/usr/bin/entrypoint.sh"]

# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]
Enter fullscreen mode Exit fullscreen mode

Reference File on
Github

Adding a Gemfile

Next we will deviate slightly from the above Docker quickstart. Instead
of using Rails 5 we'll use Rails 6.

Create a Gemfile with the following contents:

# Gemfile
source 'https://rubygems.org'
gem 'rails', '~> 6'
Enter fullscreen mode Exit fullscreen mode

Reference File on Github

Then add an empty Gemfile.lock

touch Gemfile.lock
Enter fullscreen mode Exit fullscreen mode

Adding a package.json

There are a few options to generate your package.json so lets keep it
simple, create a file with the following settings:

{
  "_filename": "package.json",
  "name": "myapp",
  "private": true,
  "version": "0.1.0"
}
Enter fullscreen mode Exit fullscreen mode

Reference File on
Github

Also, add an empty yarn.lock because Rails uses yarn by default.

touch yarn.lock
Enter fullscreen mode Exit fullscreen mode

Adding entrypoint.sh

Now lets create an entrypoint.sh script to fix a server issue with
Rails.

#!/bin/bash
# entrypoint.sh

set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /myapp/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"
Enter fullscreen mode Exit fullscreen mode

Reference File on
Github

Adding docker-compose.yml

Finally, lets add a docker-compose.yml with the following content:

# docker-compose.yml

version: "3"

services:
  web:
    environment:
      NODE_ENV: development
      RAILS_ENV: development
      WEBPACKER_DEV_SERVER_HOST: 0.0.0.0
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: example

    build:
      context: .
      args:
        USER_ID: 1000
        GROUP_ID: 1000
        APP_DIR: /home/user/myapp

    command: bash -c "rm -f tmp/pids/server.pid &&
      ./bin/webpack-dev-server &
      bundle exec rails server -p 3000 -b '0.0.0.0'"

    volumes:
      # make sure this lines up with APP_DIR above
      - .:/home/user/myapp

    ports:
      - "3000:3000"
      - "3035:3035"

    depends_on:
      - db

  db:
    image: postgres:12.2
    environment:
      POSTGRES_PASSWORD: example
    volumes:
      - db_data:/var/lib/postgresql/data

volumes:
  db_data:
Enter fullscreen mode Exit fullscreen mode

Reference File on
Github

Adding a .dockerignore file

Finally, its good practice to add a .dockerignore file. The
.dockerignore is very similar to .gitignore and this one will very
closely resemble your .gitignore that Rails will generate.

Create a .dockerignore file with the following contents:

# .dockerignore

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

Reference File on
Github

Prebuild Directory Structure

Your directory should look as follows:

.
├── docker-compose.yml
├── .dockerignore
├── Dockerfile
├── entrypoint.sh
├── Gemfile
├── Gemfile.lock
├── package.json
└── yarn.lock
Enter fullscreen mode Exit fullscreen mode

For reference, I have created a Github branch to represent the file
structure.

Prebuild Reference Repository Branch

Building the Project

Create the Rails app

Prior to building the docker container, you have to create the Rails app
structure. To do so, run the command below inside of your Rails project
directory.

docker-compose run --rm --no-deps web rails new . --force --no-deps --database=postgresql
Enter fullscreen mode Exit fullscreen mode

This will build a fresh Rails project for you using PostgresQL as the
database adapter.

Postbuild Directory Structure

Your Rails directory should look as follows:

.
├── app
├── babel.config.js
├── bin
├── .browserslistrc
├── config
├── config.ru
├── docker-compose.yml
├── .dockerignore
├── Dockerfile
├── entrypoint.sh
├── Gemfile
├── Gemfile.lock
├── .git
├── .gitignore
├── lib
├── log
├── package.json
├── postcss.config.js
├── public
├── Rakefile
├── README.md
├── .ruby-version
├── storage
├── test
├── tmp
├── vendor
└── yarn.lock
Enter fullscreen mode Exit fullscreen mode

Directory Structure after Rails new

Ownership Issues

You may run into ownership issues on Linux. I did my best to fix this.
In case anything still lingers, run the following:

sudo chown -R "$USER":"$USER" .
Enter fullscreen mode Exit fullscreen mode

And if you're feeling real crazy, you can setup an alias for this
command. I have mine called ownthis

alias ownthis="sudo chown -R $USER:$USER ."
Enter fullscreen mode Exit fullscreen mode

Connecting the Database

In order to connect the Database to Rails, you have to tell Rails where
to find the database. To do so, navigate to your config/database.yml
file.

Delete the contents of your config/database.yml and add the following:

# config/database.yml

default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: <%= ENV['POSTGRES_USER'] %>
  password: <%= ENV['POSTGRES_PASSWORD'] %>
  pool: 5

development:
  <<: *default
  database: myapp_development

test:
  <<: *default
  database: myapp_test
Enter fullscreen mode Exit fullscreen mode

Now you can boot the app using the following command:

docker-compose up --build
Enter fullscreen mode Exit fullscreen mode

In another terminal, run the following commands:

docker-compose run --rm web rails db:create
docker-compose run --rm web rails db:migrate
Enter fullscreen mode Exit fullscreen mode

Congratulations! You have finished the setup portion of the application!

Now you should be able to view your app by navigating to:

localhost:3000 in your browser's address bar.

You should see a message congratulating you for using Rails.

You're on Rails 6

Github Branch Prior to adding additional functionality

Using Docker

Stopping the application

To stop the application, in another terminal simply run:

docker-compose down
Enter fullscreen mode Exit fullscreen mode

Starting the application

To start the application there are two methods.

If you have added anything to the Gemfile, in order to sync the
changes, you must run the following:

docker-compose run web bundle install
docker-compose up --build
Enter fullscreen mode Exit fullscreen mode

If you have not changed anything Gemfile related but you may have
changed the docker-compose.yml file, you can simply run:

docker-compose up --build
Enter fullscreen mode Exit fullscreen mode

However, if you do not need to rebuild, you can simply run:

docker-compose up
Enter fullscreen mode Exit fullscreen mode

Extra Tips

As a simple way to get you going, anytime you see

rails [command]
Enter fullscreen mode Exit fullscreen mode

simply prepend the following:

docker-compose run --rm web rails [command]
Enter fullscreen mode Exit fullscreen mode

docker-compose exec is to be run if you have a container already
running.

docker-compose run is to be run if you do not have a container
running.

docker-compose run --rm will automatically remove the docker instance
once the command finished

Useful Commands

# builds a container
docker-compose build

# starts a container thats been built (equivalent to `rails server`)
docker-compose up

# starts and builds a container
docker-compose up --build

# runs a one-off instance
docker-compose run --rm web [command]

# runs a command inside of a running container
# `docker-compose up` needs to be running in another terminal
docker-compose exec web [command]

# stops the application
docker-compose down

# Remove orphaned containers as well
docker-compose down --remove-orphans

# run a bash instance inside of the docker-compose container
# now you can simply run commands like `rails db:migrate` without
# adding `docker-compose run web` before every command
docker-compose run --rm web /bin/bash

# Things are totally jacked up? Remove all images and containers.
# https://stackoverflow.com/a/52179797

docker rm $(docker ps -q -a) -f && docker rmi $(docker images -q) -f
Enter fullscreen mode Exit fullscreen mode

Adding additional functionality

In an effort to keep this blog post semi-short in length, I will refer
you to the Rails guide for this part as nothing will be different. Once
you're finished going through the Rails guide, come back here and we
will deploy to Heroku!

Ruby on Rails Guide to Getting
Started

You can skip to section 4.2 because everything prior to that we have
just done above.

Deployment to Heroku

First, lets create a Heroku account. To do so, head on over to their
signup page.

https://signup.heroku.com/

After creating an account, install the Heroku CLI.

Installation instructions can be found
here.

Now that you have Heroku CLI installed you can login via terminal.

heroku login
# heroku: Enter your Heroku credentials
# Email: schneems@example.com
# Password:
# Could not find an existing public key.
# Would you like to generate one? [Yn]
# Generating new SSH public key.
# Uploading ssh public key /Users/adam/.ssh/id_rsa.pub
Enter fullscreen mode Exit fullscreen mode

After you have logged in, you can now create a Heroku dyno. Basically
what this means is they will provision a server for you to host your
site. To do this, simply run the following:

heroku apps:create <Your-app-name>
# Creating ⬢ <Your-app-name>... done
# https://<Your-app-name>.herokuapp.com/ |
https://git.heroku.com/<Your-app-name>.git
Enter fullscreen mode Exit fullscreen mode

Now deployment is as simple as:

git push heroku master
Enter fullscreen mode Exit fullscreen mode

After waiting a little bit you should see something like the following:

remote: -----> Launching...
remote:        Released v6
remote:        https://<Your-app-name>.herokuapp.com/ deployed to Heroku
Enter fullscreen mode Exit fullscreen mode

To visit your site, simply run:

heroku open
Enter fullscreen mode Exit fullscreen mode

However, youre not done yet! If you got to your site and go visit the
/articles section, you will run into an error. This is because you
have not migrated the database on Heroku. To do so, run the following:

heroku run rails db:migrate
Enter fullscreen mode Exit fullscreen mode

Now you're done! Good luck with everything and I hope this was helpful!

Helpful Links below

Issues

Problems with ownership?

sudo chown -R "$USER":"$USER" .
Enter fullscreen mode Exit fullscreen mode

Things not working as expected?

docker-compose down --remove-orphans
docker-compose up --build
Enter fullscreen mode Exit fullscreen mode

Tired of the yarn install --check-files issues?
Disable it!

# config/webpacker.yml

# ...
check_yarn_integrity: false
# ...
Enter fullscreen mode Exit fullscreen mode

Alternatively, run the following to fix this issue:

docker-compose run --rm web yarn install --check-files
Enter fullscreen mode Exit fullscreen mode

No space left on device??

https://success.docker.com/article/error-message-no-space-left-on-device-in-default-machine

Postgres not updating a new name / passsword? You must first delete its
volume to tell postgres to rebuild it.

docker volume ls # lists the volumes
docker volume rm <volume-name> # removes the volume
docker volume prune [--force] # remove all unused volumes
Enter fullscreen mode Exit fullscreen mode

I know what I'm doing.

This section is meant to be the TLDR version of the above.
This will move quickly and is meant more as a reference.
To skip this section, click on the below link:

Links sections

mkdir -p new-rails-app
cd new-rails-app
touch Dockerfile docker-compose.yml entrypoint.sh \
      Gemfile Gemfile.lock yarn.lock package.json \
      .dockerignore
Enter fullscreen mode Exit fullscreen mode
# Dockerfile

# Pre setup stuff
FROM ruby:2.5.8 as builder

# Add Yarn to the repository
RUN curl https://deb.nodesource.com/setup_12.x | bash     && curl https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add -     && echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list

# Install system dependencies & clean them up
RUN apt-get update -qq && apt-get install -y \
    postgresql-client build-essential yarn nodejs \
    libnotify-dev && \
    rm -rf /var/lib/apt/lists/*

# This is where we build the rails app
FROM builder as rails-app

# Allow access to port 3000
EXPOSE 3000
EXPOSE 3035

# This is to fix an issue on Linux with permissions issues
ARG USER_ID=1000
ARG GROUP_ID=1000
ARG APP_DIR=/home/user/myapp

# Create a non-root user
RUN groupadd --gid $GROUP_ID user
RUN useradd --no-log-init --uid $USER_ID --gid $GROUP_ID user --create-home

# Remove existing running server
COPY entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh

# Permissions crap
RUN mkdir -p $APP_DIR
RUN chown -R $USER_ID:$GROUP_ID $APP_DIR


# Define the user running the container
USER $USER_ID:$GROUP_ID

WORKDIR $APP_DIR

# Install rails related dependencies
COPY --chown=$USER_ID:$GROUP_ID Gemfile* $APP_DIR/

# For webpacker / node_modules
COPY --chown=$USER_ID:$GROUP_ID package.json $APP_DIR
COPY --chown=$USER_ID:$GROUP_ID yarn.lock $APP_DIR

RUN bundle install

# Copy over all files
COPY --chown=$USER_ID:$GROUP_ID . .

RUN yarn install --check-files


ENTRYPOINT ["/usr/bin/entrypoint.sh"]

# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]
Enter fullscreen mode Exit fullscreen mode
# docker-compose.yml

version: "3"

services:
  web:
    environment:
      NODE_ENV: development
      RAILS_ENV: development
      WEBPACKER_DEV_SERVER_HOST: 0.0.0.0
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: example

    build:
      context: .
      args:
        USER_ID: 1000
        GROUP_ID: 1000
        APP_DIR: /home/user/myapp

    command: bash -c "rm -f tmp/pids/server.pid &&
      ./bin/webpack-dev-server &
      bundle exec rails server -p 3000 -b '0.0.0.0'"

    volumes:
      # make sure this lines up with APP_DIR above
      - .:/home/user/myapp

    ports:
      - "3000:3000"
      - "3035:3035"

    depends_on:
      - db

  db:
    image: postgres:12.2
    environment:
      POSTGRES_PASSWORD: example
    volumes:
      - db_data:/var/lib/postgresql/data

volumes:
  db_data:
Enter fullscreen mode Exit fullscreen mode
#!/bin/bash
# entrypoint.sh

set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /myapp/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"
Enter fullscreen mode Exit fullscreen mode
# Gemfile

source 'https://rubygems.org'
gem 'rails', '~> 6'
Enter fullscreen mode Exit fullscreen mode
{
  "_filename": "package.json",
  "name": "myapp",
  "private": true,
  "version": "1.0.0"
}
Enter fullscreen mode Exit fullscreen mode
# .dockerignore

# .dockerignore

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

After setting up the above files, then run:

docker-compose run --rm --no-deps web rails new . --force --no-deps --database=postgresql
Enter fullscreen mode Exit fullscreen mode

Now run:

docker-compose build
Enter fullscreen mode Exit fullscreen mode

After building the image, then install webpacker:

docker-compose run --rm web rails webpacker:install
Enter fullscreen mode Exit fullscreen mode

This will provide you with a base for webpacker.

Now setup the database in the config/database.yml

# config/database.yml

default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  username: <%= ENV['POSTGRES_USER'] %>
  password: <%= ENV['POSTGRES_PASSWORD'] %>
  pool: 5

development:
  <<: *default
  database: myapp_development

test:
  <<: *default
  database: myapp_test
Enter fullscreen mode Exit fullscreen mode

Next create the database.

docker-compose run --rm web bash -c "rails db:create && rails db:migrate"
Enter fullscreen mode Exit fullscreen mode

Finally, start the app:

docker-compose up
Enter fullscreen mode Exit fullscreen mode

Now you can view it on localhost:3000

Now, to deploy the app, simply do the following:

heroku login
heroku apps:create <App-name>
git push heroku master
heroku run rails db:migrate
Enter fullscreen mode Exit fullscreen mode

And thats it ! Were all set and deployed.

Source Code on Github

Deployed Application

Rails

Ruby on Rails Homepage

Ruby on Rails Getting Started Guide

Webpacker Gem

Docker

Docker Compose with Rails

PostgresQL

PostgresQL Homepage

Heroku

Heroku Homepage

Heroku with Rails
Deployment

Found something wrong? Submit a pull request!

Blog Source

Rails App Source

Top comments (0)