Starting a Rails app using vscode containers
Tags: ruby, rails, vscode, docker
Published: 2020-08-30 04:01:26

I had been using Docker a lot in my development workflow for a while. Currently, I always start creating a dockerfile with a docker-compose file to start a new project, and this always adds another layer of work before starting a new project. 

Recently, **VSCode** has been improving its docker integration with [dev containers](https://code.visualstudio.com/docs/remote/containers), this feature makes the process of working with containers easier and gives a smoother integration between the editor and the workspace inside the container (Improving compatibility with extensions, isolated configurations and easier debugging).

In this post, we are going to start a rails application with a PostgreSQL database using dev containers.

## Pre-requisites

- [Docker](https://docs.docker.com/get-docker/) and  [docker compose](https://docs.docker.com/compose/install/) installed
- [WSL2](https://code.visualstudio.com/blogs/2019/09/03/wsl2) installed if you are using windows
- [Remote containers](https://github.com/Microsoft/vscode-remote-release) extension installed
- [VSCode](https://code.visualstudio.com/) with [remote containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension installed

## Let's get started

Open your terminal and add a new folder using the terminal  `mkdir rails-example`, now `cd` into the directory and open the folder with VSCode

```bash
cd rails-example
code .
```

On the editor, press `ctrl+shift+p`. This will open the command panel. Look for the "Add Development Container Configuration Files.." option.

![Add dev container](https://dev-to-uploads.s3.amazonaws.com/i/5xp46re4d94rsz27xd0c.png)

This will open another panel, click on the "Show All Definitions" option and select "Ruby on Rails". There are more configurations for other languages, and many more setups in progress (For instance, I've seen an Elixir + Phoenix configuration on a pull request in the Github page of the extension).

![Rails dev configuration](https://dev-to-uploads.s3.amazonaws.com/i/khgyn8j1rxvhvxgi6g0c.png)

This will add two files inside the .devcontainer folder. Inside devcontainer.json there are certain arguments that we can change, such as the ruby and node versions. We can open this folder inside the container with this configuration by pressing `ctrl+shift+p` again and selecting the "Reopen in Container" option. Wait a couple of minutes and then the editor should reopen with the Dev container tag at the bottom.

![Reopen Folder](https://dev-to-uploads.s3.amazonaws.com/i/5824w80gox8f0l8cpm04.png)

Open your editor terminal and type `ruby -v && rails -v`. If the terminal shows both versions you are good, now you have a ruby on rails container with everything you need to start building a rails application... well, almost.PostgreSQL is required for this application, so you need to add your own docker-compose and extend the dev container configuration JSON file. This will allow you to add more services in the future such as Redis or Elasticsearch.

## Extending the default configuration

Inside the `.devcontainer` folder, add a new file named `docker-compose.yml` the following content:
```yaml
version: '3'

volumes: 
  postgres_data:

services:
  app:
    # See https://aka.ms/vscode-remote/containers/non-root for details.
    user: vscode

    build: 
      context: ..
      dockerfile: .devcontainer/Dockerfile
      args:
        # Update 'VARIANT' to pick a Ruby version: 2, 2.7, 2.6, 2.5
        VARIANT: 2.7
        USER_UID: 1000
        USER_GID: 1000
        NODE_VERSION: lts/*

    volumes:
      - ..:/workspace:cached
      - $HOME/.ssh/:/home/vscode/.ssh/ # Mount the ssh folder to authenticate with github
      
    # Overrides default command so things don't shut down after the process ends.
    command: sleep infinity
    
    links: 
      - db
    
  db:
    image: postgres
    restart: unless-stopped
    volumes: 
      - postgres_data:/var/lib/postgresql/data
    ports: 
      - 5432:5432
    environment:
      POSTGRES_PASSWORD: LocalPassword
```
This docker-compose extends the dev container with PostgreSQL added as a service. Also, there is a volume mount for your `.ssh` folder in order to authenticate with Github inside the container.

Now we need to edit  the `devcontainer.json` file  with the following code to connect your docker-compose service:
```json
{
	"name": "Ruby on Rails With PostgreSQL",
	"dockerComposeFile": "docker-compose.yml",
	"service": "app",
	"workspaceFolder": "/workspace",
	// Set *default* container specific settings.json values on container create.
	"settings": { 
		"terminal.integrated.shell.linux": "/bin/bash"
	},

	// Add the IDs of extensions you want to be installed when the container is created.
	"extensions": [
		"rebornix.Ruby"
	],
	
	// Use 'forwardPorts' to make a list of ports inside the container available locally.
	"forwardPorts": [3000],

	// Uncomment to connect as a non-root user. See https://aka.ms/vscode-remote/containers/non-root.
	"remoteUser": "vscode",
}
```
After adding these files you need to rebuild the image and reopen the folder in the container. Now, when you are inside the dev container, type the following command to create a new rails app:
```bash
rails new . -d postgresql
```
After the generation is completed, edit the `config/database.yml` with the credentials of the database service `db`:
```yaml
default: &default
  adapter: postgresql
  encoding: unicode
  host: db
  user: postgres
  password: LocalPassword
  # For details on connection pooling, see Rails configuration guide
  # https://guides.rubyonrails.org/configuring.html#database-pooling
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
```
After adding these database credentials  run `rails db:create` to create the database.

Now you are ready to start the rails app with `rails s` command, after that visit [http://localhost:3000/](http://localhost:3000/) to see the rails app running.
![Rails S](https://dev-to-uploads.s3.amazonaws.com/i/zo71ma0y2nr1mlbjlwwh.png)
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/mre77zah89misa4k3s80.png)

## Conclusion

This was a little example of how to get started with dev-containers, which is an awesome feature that can be very helpful to start dev environments quickly between members of a team, reducing the amount of work installing libraries and dependencies, working in projects with different versions and more.

This is my first post and I'm not a native English speaker, so I'm open to any feedback and make adequate corrections.