Creating Rails API from scratch (with PostgreSQL and Docker)
Published: 2023-01-26 22:06:32


To create a Rails API app that uses a PostgresQL database and run it using Docker Compose, you will need to complete the following steps:
 
> Must be installed ruby 3.0.x and docker

**1** Install rails gem

```
gem install rails
```
**2** Create a new Rails API app by running the command
```
rails new my_api --api -d postgresql
```
**3** Check your ruby version in Gemfile. The Rails version you are using may not support the latest Ruby version. Updating the Ruby version specified in the Gemfile to '~> 3.0' allows you to use a version of Ruby that is compatible with the version of Rails you are using.

```
ruby '~> 3.0'
```
**4** Create a `Dockerfile` file in the root of your app with the following contents:

```
FROM ruby:3.0

RUN apt-get update -qq && apt-get install -y nodejs postgresql-client

RUN mkdir /my_api
WORKDIR /my_api

COPY Gemfile /my_api/Gemfile
COPY Gemfile.lock /my_api/Gemfile.lock

RUN bundle install

COPY . /my_api

CMD ["rails", "server", "-b", "0.0.0.0"]
```

The `FROM` instruction sets the base image for the `Dockerfile`, in this case `ruby:3.0`.

The `RUN` instruction runs a command in a new layer added to the image. The first `RUN` command updates the package lists and installs `nodejs` and `postgresql-client` packages.

The `RUN` command that follows creates a new directory called `/my_api`. The `WORKDIR` instruction sets the working directory for any `RUN`, `CMD`, `ENTRYPOINT`, `COPY` and `ADD` instructions that follow it in the `Dockerfile`.

The `COPY` instruction copies files from the host file system to the container file system. The first `COPY` command copies the `Gemfile` and `Gemfile.lock` from the host to the `/my_api` directory in the container.

The next `RUN` command runs `bundle install` command to install the dependencies specified in the `Gemfile` and `Gemfile.lock` files.

The second `COPY` command copies all the files from the current directory on the host to the `/my_api` directory in the container.

The `CMD` instruction provides default command to execute when a container is created from the image. The command `["rails", "server", "-b", "0.0.0.0"]` runs the rails server command with the option `-b` set to `0.0.0.0`, which means that the server will bind to all available network interfaces.

**5** Create a `docker-compose.yml` file in the root of your app as well. It should contain the following:

```
version: '3'
services:
  db:
    image: postgres
    environment:
      POSTGRES_USER: my_api
      POSTGRES_PASSWORD: my_api
      POSTGRES_DB: my_api_development
    ports:
      - "5432:5432"
  web:
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    environment:
      POSTGRES_USER: my_api
      POSTGRES_PASSWORD: my_api
      POSTGRES_DB: my_api_development
    volumes:
      - .:/my_api
    ports:
      - "3000:3000"
    depends_on:
      - db

```
The `version` field specifies the version of the Compose file format. In this case, it is version 3.

The services field defines all the services that make up the application. It has two services defined: `db` and `web`.

The `db` service uses the `postgres` image and sets environment variables for the PostgreSQL user, password, and database name to be used. The `ports` field maps the host's port 5432 to the container's port 5432, allowing access to the PostgreSQL instance running in the container.

The `web` service uses the `build` field to specify that the image should be built from the current directory (`.`) and the `command` field to specify command that will be executed when the container starts. This command removes the server.pid file and runs the `rails server` command with options to listen on port 3000 and bind to all available network interfaces. It also sets environment variables for the PostgreSQL user, password, and database name to be used, which should match with the `db` service's environment variables.

The `volumes` field mount the current directory on the host to the `/my_api` directory in the container, allowing changes made on the host to be reflected in the container.

The `ports` field maps the host's port 3000 to the container's port 3000, allowing access to the Rails application running in the container.

The `depends_on` field specifies that the `web` service depends on the `db` service. This means that Compose will ensure that the `db` service is running before starting the `web` service.

**6** Update the `config/database.yml` file to include the necessary information to connect to your PostgresQL database.

```
development:
  <<: *default
  database: <%= ENV['POSTGRES_DB'] %>
  username: <%= ENV['POSTGRES_USER'] %>
  password: <%= ENV['POSTGRES_PASSWORD'] %>
  host: db
```
**7** Add this simple endpoint to `config/routes.rb`

```
Rails.application.routes.draw do
  get '/status', to: 'status#index'
end
```
**8** Create a controller `status_controller.rb` in `app/controllers` with this content

```
class StatusController < ApplicationController
  def index
    render json: {status: 'OK'}
  end
end
```
Run `docker-compose build` to build the images for your app and database
Run `docker-compose up` to start your app and database.

Check the first API endpoint in your Rails app: 

![the first API endpoint in your Rails app](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dguesg2ejinz68x789jt.png)