This guide shows and explains bootstrapping new Rails application using Docker. This way you don’t have to install Ruby and other tools on your host.

In my case I want to use PostgreSQL as a default database. The magic command is:

docker run --rm -v $PWD:/app -w /app ruby:2.5.1-alpine /bin/sh -c 'apk add --update build-base postgresql-dev && gem install rails -v "5.2.0" && rails new . --database=postgresql'

How does it work?

Let’s break the command down into parts:

  • docker run - this creates a new Docker container
  • --rm - remove the image after running rails new
  • -v $PWD:/app - mount current directory in /app
  • -w /app - set default work directory to /app
  • ruby:2.5.1-alpine - image identifier of a ruby official repository image tagged as 2.5.1-alpine. 2.5.1 refers to the Ruby version. alpine is a lightweight Linux distribution that weights only around 5MB.
  • /bin/sh -c '...' - a command to run in the Docker container. We need to run multiple commands (combined with &&). The only way to achieve that is to run them in a shell. We use sh instead of bash because by default Alpine doesn’t have bash installed.
  • apk add --update build-base postgresql-dev - installs Rails and pg gem (used for PostgreSQL) dependencies
  • gem install rails -v "5.2.0" - installs Rails
  • rails new . --database=postgresql - bootstraps Rails application using Postgres as default DB. Finally!

Interactive rails new

If you want to experiment with rails new parameters you can use an interactive shell instead.

docker run --rm -it -v $PWD:/app -w /app ruby:2.5.1-alpine /bin/sh

Please notice new docker option: -it. These are two separate options: -i (also--interactive) and -t (also --tty). Usually you want to use them together when running anything interactive.

Custom application name

rails new required PATH argument not only determines the path but also is used to set the application name. The app name is used in config/application.rb to define a top module. Unfortunately for some reason it’s not possible to provide application name as an option. To work around this issue use custom volume mountpoint and absolute path of current directory instead of .

docker run --rm -v $PWD:/$(basename $PWD) -w /$(basename $PWD) ruby:2.5.1-alpine /bin/sh -c 'apk add --update build-base postgresql-dev && gem install rails -v "5.2.0" && rails new $PWD --database=postgresql'

File permissions in Linux host volumes

If you are using a Linux host to run Docker all files created by rails new are owned by root on your local machine.

The problem is fixable using sudo chown but it’s just a temporary solution. The only permit solution is to use user namespace that will help you with remapping your host user to Docker.

My post about Linux user namespaces shows how to fix this properly.

This problem doesn’t exist on Mac OS or Windows where NFS is used to mount local volumes.