Next.js 13 + Ruby on Rails + Dockerの開発環境を構築する

# はじめに

- エンジニア歴半年の備忘録
- いろんな記事を参考に作ってます（マジで感謝）

# やりたいこと

- Next.js 13 + Railsを使ったWebアプリを作りたい
- それをDockerの仮想環境で作りたい

# バージョン

- Ruby 3.2.2
- Rails 7.0.6
- node.js 18
- next.js 13

# 早速構築する

以下のディレクトリ構造をまずは作る。

（SuwaSystemsとは今回作ったアプリの固有名詞です。気にしないで）

```
SuwaSystems
├── docker 
│   ├── db // dbコンテナのマウント先
│   └── redis
│       └── data
├── suwasystems-backend
│   ├── // ここにRails
└── suwasystems-app
		└── // ここにNext.js
```

## Next.jsを入れる

フロントエンド(今回はapp)のディレクトリに移動して

```jsx
> npx create-next-app --typescript
```

`—typescript`のオプション（`—ts`でもおけ）を付けるとTypeScriptの形式でコードを生成してくれる。

## Railsを入れる

バックエンド(今回はbackend)のディレクトリに移動して

```jsx
> rails new project-backend --skip-spring --api
```

で完成。

## Gitの調節

各Next.jsとRailsのフォルダには~~めんどくさい~~ことに初期から.gitが用意されている。各ディレクトリに移動して以下を実行、削除しておく。

```jsx
> rm -rf .git
```

`.gitignore`の統合を済ませておくとなおよし。（バラバラでも機能するが見た目が良くない）

# Docker環境を構築する

さっきのディレクトリに以下を追加する

```
SuwaSystems
├── docker
│  
├── suwasystems-backend
│   ├── // railsのファイル諸々
│   ├── Dockerfile // 追加
│   ├── Gemfile.   // 追加
│   └── Gemfile.lock  // 追加
│
├── docker-compose.yml // 追加
├── .env //追加
│
└── suwasystems-app
		├── // next.jsのファイル諸々
		└── Dockerfile // 追加
```

`docker-compose.yml`はルートディレクトリに一つ、`Dockerfile`はフロントとバックに一つずつ置いておきます。

`docker-compose.yml`:

```yml
version: '3.8'

services: 
  front:                             # Next.js用コンテナ
    build:
      context: ./suwasystems-app/
    volumes:
      - ./suwasystems-app:/app       # ボリュームのバインド設定
    command: 'yarn dev'              # コンテナ起動時に実行されるコマンド
    ports:
      - "8080:3000"                  # host側の8080ポートをコンテナの3000ポートに対してフォワード
  back:                              # Rails用コンテナ
    build:
      context: ./suwasystems-backend/
    ports:
      - 3000:3000
    volumes:
      - ./suwasystems-backend:/app   # ボリュームのバインド設定
    environment:                     # 環境変数の設定　.envファイルから取得
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
      MYSQL_USER: ${MYSQL_USER}
      MYSQL_HOST: ${MYSQL_HOST}
    depends_on:                      # コンテナの依存設定
      - db
      - redis
  db:                                # Mysql用コンテナ
    image: mysql:8.0.33
    environment:                     # 環境変数の設定　.envファイルから取得
      MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
      MYSQL_DATABASE: ${MYSQL_DATABASE}
      MYSQL_PASSWORD: ${MYSQL_PASSWORD}
    volumes:
      - "./docker/db:/var/lib/mysql"
  redis:                              # redis用コンテナ
    image: "redis:latest"
    volumes:
      - "./docker/redis/data:/data"
```

`.env`: 

```jsx
MYSQL_ROOT_PASSWORD=password
MYSQL_DATABASE=testdb
MYSQL_PASSWORD=password
MYSQL_USER=root
MYSQL_HOST=db
```

## フロント用`Dockerfile`

```yml
FROM node:18

RUN /bin/bash &&\
    apt-get -y update &&\
    apt-get -y upgrade &&\
    npm install -g npm

WORKDIR /app

CMD /bin/bash
```

## バック用`Dcokerfile`

```yml
FROM ruby:3.2

RUN mkdir /app
WORKDIR /app
RUN apt-get update -qq && apt-get install -y default-mysql-client
ADD Gemfile /app/Gemfile
ADD Gemfile.lock /app/Gemfile.lock
RUN gem update && \
    bundle install
ADD . /app

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

## `Gemfile`の更新

```yml
# Use sqlite3 as the database for Active Record
# gem "sqlite3", "~> 1.4"

# Use mysql as the database for Active Record
gem "mysql2"
```

今回はmysqlを使うので、sqliteをコメントアウトしてmysql2を追加します

## `database.yml`の更新

`/config/database.yml`を更新します。

```yml
default: &default
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: <%= ENV["MYSQL_USER"] %>
  password: <%= ENV["MYSQL_PASSWORD"] %>
  host: <%= ENV["MYSQL_HOST"] %>

development:
  <<: *default
  database: <%= ENV["MYSQL_DATABASE"] %>
# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  <<: *default
  <<: *local
  database: project_test

production:
  <<: *default
  url: <%= ENV['DATABASE_URL'] %>
  socket: /tmp/mysql.sock
```

## `.gitignore`の更新

nextとrailsの初期設定にプラスして、以下を入れるといいかもしれません（ここはお好みで）

```yml
# vscode
.vscode

# docker
/docker/db
```

# 起動

ここまできたら起動してみましょう

```jsx
> docker-compose up -d --build
```

# 確認

## Next.jsの確認

http://localhost:8080/

でNext.jsの初期画面が確認できたらフロントの確認は完了です。

![スクリーンショット 2023-09-18 0.58.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3504047/c01970c5-562f-cecf-da6d-5164613642a1.png)


## Railsの確認

http://localhost:3000/

![スクリーンショット 2023-09-18 1.13.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3504047/fb07c891-9eab-e86f-f7ee-b0276787260b.png)


railsの画面も表示されたら完成です！！
お疲れ様でした！！！！！！！！！！！！！！

# エラー対処備忘録

### エラー：`error Couldn't find a package.json file in "/app”`

`docker-compose.yml`のマウントするボリューム(volumes:)の指定はフレームワークの設定を含むディレクトリを指定しないとエラーになります。

```yml
services: 
  front:                             # Next.js用コンテナ
    build:
      context: ./suwasystems-app/
    volumes:
      - ./suwasystems-app/app:/app  
    command: 'yarn dev'              
    ports:
      - "8080:3000"                 
```

上記は`/suwasystems/app`ディレクトリに`package.json`が無いためエラーが出ます。

```yml
volumes:
    - ./suwasystems-app/:/app
```

解決方法は簡単。こうするだけですね。

### エラー：`Rack app ("GET /" - (172.25.0.1)): #<Psych::AnchorNotDefined:"Cannot load database configuration:\nAn alias referenced an unknown anchor: local">`

`config/database.yml`の設定ミスをするとこうなります。

対処法は簡単。`&local`と続くアンカーを以下のようにしっかり定義してあげるだけ（俺は`&default`になってた）

```yaml
default: &local
  adapter: mysql2
  encoding: utf8mb4
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: <%= ENV["MYSQL_USER"] %>
  password: <%= ENV["MYSQL_PASSWORD"] %>
  host: <%= ENV["MYSQL_HOST"] %>

development:
  <<: *local
  database: <%= ENV["MYSQL_DATABASE"] %>
# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
test:
  <<: *local
  database: project_test

production:
  <<: *local
  url: <%= ENV['DATABASE_URL'] %>
  socket: /tmp/mysql.sock
```

# 参考
https://qiita.com/devactken/items/7f26ab5096229d756a66

https://zenn.dev/kei178/articles/43172ba33eece4

https://qiita.com/shinKoala99/items/5c1f21996b7f3980cc06