Rails 7 x React 18(Javascript) x Docker 環境構築

# はじめに
みなさん、こんにちは **torihazi**です

つい最近までReactを勉強していたのですが、

最近Rails ReactのSPAを勉強することになり

これまで扱っていたDockerを使って環境構築をしてみることにしました。

Javascriptなので、実用性は低いかもしれませんが

まずはJavascript！という方は参考にしてください！

実務未経験なのでディレクトリ構成など、おかしいところあるかもしれません

そんな時はこそっと教えてください！

# 環境
```
docker compose v2.28.1-desktop.1
docker engine 27.0.3
```

# ディレクトリ構成について
```
|- docker-compose.yml
|- Dockerfile.back
|- Dockerfile.front
|- front(git管理)
   |- 色々(create-react-appでこれから作る)
|- back(git管理)
   |-Gemfile
   |-Gemfile.lock
   |-entrypoint.sh
   |- 色々(rails new でこれから作る)
```

# 必要になるファイル
```yaml:docker-compose.yml
version: "3"
services:
  db:
    image: postgres:latest
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: postgres
      POSTGRES_DB: myapp_development
    ports:
      - "5432:5432"

  back:
    build:
      context: .
      dockerfile: Dockerfile.back
    volumes:
      - type: bind
        source: ./back
        target: /myapp
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    ports:
      - "3001:3000"
    environment:
      DATABASE_PASSWORD: postgres
      TZ: Asia/Tokyo
      RAILS_ENV: development
    depends_on:
      - db

  front:
    build:
      context: .
      dockerfile: Dockerfile.front
    volumes:
      - type: bind
        source: ./front
        target: /usr/src/app
    command: bash -c "npm start"
    ports:
      - "3000:3000"

volumes:
  postgres_data:
```

```Dockerfile:Dockerfile.back
FROM ruby:3.2.1
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs

ENV DIR /back

WORKDIR /myapp
COPY ${DIR}/Gemfile /myapp/Gemfile
COPY ${DIR}/Gemfile.lock /myapp/Gemfile.lock
RUN bundle install
COPY ${DIR} /myapp

# Add a script to be executed every time the container starts.
COPY ${DIR}/entrypoint.sh /usr/bin/
RUN chmod +x /usr/bin/entrypoint.sh
ENTRYPOINT ["entrypoint.sh"]
EXPOSE 3000

# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]
```


```Ruby: Gemfile
source "https://rubygems.org"
gem "rails", "~> 7.1.3", ">= 7.1.3.4"
```

```Ruby:Gemfile.lock
何も記載しない
```

```sh:entrypoint.sh
#!/bin/bash
set -e

# Remove a potentially pre-existing server.pid for Rails.
rm -f /myapp/tmp/pids/server.pid

# Then exec the container's main process (what's set as CMD in the Dockerfile).
exec "$@"
```


```Dockerfile:Dockerfile.front
FROM node:latest
WORKDIR /usr/src/app
```


# 環境構築
### 1. docker-compose.ymlがある階層でコマンド実行
```
# docker compose build
```
### 2.Railsプロジェクト立ち上げ
```
# docker compose run --rm back rails new . --api --force --no-deps --database=postgresql --skip-docker
```
### 3.config/database.ymlに追記
```yml:databse.yml
default: &default
  adapter: postgresql
  encoding: unicode
  # For details on connection pooling, see Rails configuration guide
  # https://guides.rubyonrails.org/configuring.html#database-pooling
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  # ここから
  host: db
  username: postgres
  password: <%= ENV.fetch("DATABASE_PASSWORD") %>
  port: 5432
  # ここまで
  
```

### 4.再ビルドしてコンテナを立ち上げる
```
# docker compose up --build (-d オプションつけたければどうぞ)
```
自分はなんとなくログが見たいので -dはつけません。
ちなみにfront側はまだいじってないのでエラーが出て立ち上がらないと思います。
上がらないことは期待値です。

```log:ログ抜粋
front-1  | npm error code ENOENT
front-1  | npm error syscall open
front-1  | npm error path /usr/src/app/package.json
front-1  | npm error errno -2
```

### 5.localhostにアクセス
http://localhost:3001 にアクセスして下記画像が出ればOK
![スクリーンショット 2024-07-07 23.21.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2567812/883cdec9-c11e-f176-ae02-155f1f7d723a.png)

### 6.front側を立ち上げる
立ち上げたコンテナ群を落としたあと、create-react-appを実行します
```
ctrl + c
# docker compose down
# docker compose run --rm front npx create-react-app .
```

### 7.front側の不要ファイル削除
srcディレクトリ配下の
- App.test.js
- logo.svg
- reportWebVital.js
- setupTests.js
は不要なので削除します。

![スクリーンショット 2024-07-07 23.29.36.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2567812/2c927542-98d9-4f9a-a5d0-00f88ec7e91e.png)

### 8.front側の一部ファイル修正
修正するファイルはApp.jsとindex.jsです。
```javascript:App.js
import './App.css';

function App() {
  return (
    <div className="App">HelloWorld</div> 
  );
}

export default App;
```

```javascript:index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);
```

### 9.全部立ち上げる
```
# docker compose up
```

そうすることで
http://localhost:3001 ではRailsの画面が
http://localhost:3000 ではReactの画面が表示されます。
なおReactの画面は上部にHelloWorldが表示されるのみです。

![スクリーンショット 2024-07-07 23.38.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2567812/4749f64c-9baf-c25e-3369-4c0cb9a4ac4d.png)

### 10.おまけ
あとはback、frontごとに`git init`してGit管理するもよしです。
ただCORSの設定だけは必要だと思うのでそれだけ入れようと思います。

流れとしては`rack-cols`というgemを入れるくらいです。
その後のfrontからfetchか何かしてCORSエラー出さずに取ってこれてるかは
各自でお願いします。。

### 11.Rails側の設定
```
ctrl +c
# docker compose down
```

```ruby:Gemfile
# 36行目くらいのをコメントアウト外す
# Use Rack CORS for handling Cross-Origin Resource Sharing (CORS), making cross-origin Ajax possible
gem "rack-cors"
```

```ruby:config/initializers/cors.rb
# この行があると思うのでコメントアウト外す
Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins "example.com"

    resource "*",
      headers: :any,
      methods: [:get, :post, :put, :patch, :delete, :options, :head]
  end
end
```

# 終わりに
以上で、実行環境ができたのではないかと思います。

まだまだ「ここ、実務じゃ使わないよ」とか

ここおかしいよ、というところあるかと思います。

これからももっと勉強を重ねていこうと思うので

そこんところは多めに見てくれると助かります。