Rails on Docker（alpine）でAPIコンテナをつくってみた

# はじめに
RailsにはAPIモードが存在します。バックエンド側でRailsを使いたい場合に便利そう。
この記事のGoalは、Rails on DockerでAPIコンテナを構築することにします。DBはPostgreSQLを利用します。最後にcurlでちゃんとAPIとして使えるかテストもしておきます。

`docker`や`docker-compose`は準備済みの前提です。

# ゴール
- Rails on Docker（APIモード）を構築する
- curlでAPIが正常に動作するかテストする

# 目次
1. Rails on Dockerの下準備
2. rails newでAPIアプリの作成
3. 【TEST】 CRUDをテストしてみる

# 1. Rails on Dockerの下準備
まずは`Dockerfile`を作っていきます。「[Quickstart: Compose and Rails | Docker Documentation](https://docs.docker.com/compose/rails/)」でも書かれているように

- Dockerfile
- docker-compose.yml
- Gemfile
- Gemfile.lock

あたりを用意します。これらのファイルは作成するアプリのルートディレクトリにおいときます。

```Dockerfile:Dockerfile
FROM ruby:2.6.3-alpine3.10

ENV RUNTIME_PACKAGES="linux-headers libxml2-dev make gcc libc-dev nodejs tzdata postgresql-dev postgresql" \
    DEV_PACKAGES="build-base curl-dev" \
    HOME="/app_name" \
    LANG=C.UTF-8 \
    TZ=Asia/Tokyo

WORKDIR $HOME

ADD Gemfile $HOME/Gemfile
ADD Gemfile.lock $HOME/Gemfile.lock

RUN apk update && \
    apk upgrade && \
    apk add --update --no-cache $RUNTIME_PACKAGES && \
    apk add --update --virtual build-dependencies --no-cache $DEV_PACKAGES && \
    bundle install -j4 && \
    apk del build-dependencies

ADD . $HOME

CMD ["rails", "server", "-b", "0.0.0.0"]
```
imageの軽量化をめざしてalpine使っちゃってます。

```yaml:docker-compose.yml
version: "3"

services:
  db:
    container_name: app_name_db
    image: postgres:11.4-alpine

  app:
    container_name: app_name_app
    build: .
    volumes:
      - .:/app_name
    ports:
      - 3000:3000
    depends_on:
      - db
```
こちらもPostgreSQLをalpineで。

```Gemfile:Gemfile
source 'https://rubygems.org'
gem 'rails', '~>5'
```

Gemfileはこんな感じで。
Gemfile.lockはファイルを作っておくだけ。

```
$ touch Gemfile.lock
```

# 2. rails newでAPIアプリの作成
```
$ docker-compose run app rails new . -f -d postgresql --api
```
ポイントは`--api`の部分です。このオプションをつけることでapiアプリに不要なものが生成されなくなります。
あとはDB作成しておきます。

```yaml:config/database.yml
#####
default: &default
  adapter: postgresql
  encoding: unicode
  host: db            # add
  username: postgres  # add
  password:           # add
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> 
#####
```

```
$ docker-compose build
$ docker-compose run --rm app rails db:create
$ docker-compose up -d
```

`http://localhost:3000`にアクセスしていつものRails Hello Worldページが出たら成功です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/254216/617f845b-c145-7282-3e33-8d74a3825dd5.png)

このページは表示されますが、APIモードでアプリを作っているので他のviewをつくるのは面倒です。scaffoldしてもviewができたりはしないです。

一旦コンテナ停止しときます。

```
$ docker-compose down
```

# 3. 【TEST】 CRUDをテストしてみる
テスト用に適当にモデルを作ってみます。`name`をもつ`User`モデルにします。

```
$ docker-compose run --rm app rails generate scaffold user name:string
$ docker-compose run --rm app rails db:migrate
$ docker-compose up -d
```

## 3-1. Create
```
$ curl -X POST http://localhost:3000/users -d 'user[name]=test1'
{"id":1,"name":"test1","created_at":"YYYY-MM-DD","updated_at":"YYYY-MM-DD"}

$ curl -X POST http://localhost:3000/users -d 'user[name]=test2'
{"id":2,"name":"test2","created_at":"YYYY-MM-DD","updated_at":"YYYY-MM-DD"}
```
おー、ユーザーできた。

## 3-2. Read
```
$ curl -X GET http://localhost:3000/users
[{"id":1,"name":"test1","created_at":"YYYY-MM-DD","updated_at":"YYYY-MM-DD"},{"id":2,"name":"test2","created_at":"YYYY-MM-DD","updated_at":"YYYY-MM-DD"}]

$ curl -X GET http://localhost:3000/users/1
{"id":1,"name":"test1","created_at":"YYYY-MM-DD","updated_at":"YYYY-MM-DD"}
```
`index`の取得も`show`の取得もできたぜ。ちなみにGETの場合は`-X GET`オプションはなくてもOK。

## 3-3. Update
```
$ curl -X PUT http://localhost:3000/users/1 -d 'user[name]=test3'
{"id":1,"name":"test3","created_at":"YYYY-MM-DD","updated_at":"YYYY-MM-DD"}
```
`id=1`のユーザーの`name`が`test1`から`test3`にアップデートされましたー。

## 3-4. Delete
```
$ curl -X DELETE http://localhost:3000/users/1

$ curl -X GET http://localhost:3000/users
{"id":2,"name":"test2","created_at":"YYYY-MM-DD","updated_at":"YYYY-MM-DD"}
```
`id=1`のユーザーが消えました！

# Reference

- [DockerComposeでコンテナベースのRailsアプリを作成してそのままHerokuにデプロイする - Qiita](https://qiita.com/akirakudo/items/16a01271b0a39316e439)
- [RailsのためのCurlコマンドの備忘録 - Qiita](https://qiita.com/joji/items/2dcee37c482fbab592a8)