ume

Docker✖️Rails8✖️Next.js15(SPA環境)の環境構築

前書き

  • 私の設定が間違っている場合ご指摘ください。

pc環境

全体像

  1. railsとnext.jsのプロジェクトをサブモジュール化

  2. railsの設定(データベース接続)

  3. docker-compose.ymlファイル作成

  4. フロントエンドとバックエンドをAPI連携

  5. 連携ができたか確認する

railsとnext.jsのプロジェクトをサブモジュール化

loveenglish.hatenablog.com

railsの設定(データベース接続)

全体像
  1. 環境変数を定義するファイル「.env」ファイル作成

  2. railsのconfig/database.ymlを編集

環境変数を定義するファイル「.env」ファイル作成

現状のディレクトリ構造

SpeCon/
│
├── back/
│   └── spe-con/ #⇦ここで.envファイルを作成する
│       └── (Railsプロジェクトのファイル群)
│
└── front/
    └── spe-con/
        └── (Next.jsプロジェクトのファイル群)

バックエンドのプロジェクトのルートで.envファイル作成

touch .env

.env(このように環境変数を定義) アカウント名、パスワード、ホスト名を定義してください

USER=任意のユーザー名(例:abcd)
PASSWORD=任意のパスワード(abcd123)
HOST=ホスト名(アプリ名)

注意:もし.envファイルを.gitignoreファイルに追加していない場合は.
.gitignoreファイルに下記を追加してください

/.env*

これでうっかり環境変数githubに載せるのを防ぎます。

またローカルの環境変数名と.envファイルの環境変数名が同じものがあった場合ローカルの環境変数が優先的に使われるのでローカルの環境変数と.envファイルの環境変数が被っていないか注意してください。
ローカルの環境変数を調べるコマンドは下記です。

printenv
railsのconfig/database.ymlを編集

config/database.ymlファイル .envで定義した(設定したユーザー名、パスワード、ホスト名)を設定

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: <%= ENV["DB"] %>
  username: <%= ENV["USER"] %>
  password: <%= ENV["PASSWORD"] %>

③docker-compose.ymlファイル作成する

SpeCon/
│
├── back/
│ └── spe-con/
│ ├── .env # 新しく追加された.envファイル
│ └── (Railsプロジェクトのファイル群)
│
├── front/
│ └── spe-con/
│ └── (Next.jsプロジェクトのファイル群)
│
└── docker-compose.yml # 新しく追加されたdocker-compose.yml

dcoker-compose.ymlファイルを作成する

touch docker-compose.yml

dcoker-compose.ymlファイルの中身

version: '3'

services:
  db:
    image: postgres:latest
    volumes:
      - postgres_data:/var/lib/postgresql/data
    environment:
      POSTGRES_DB: ${DB}
      POSTGRES_USER: ${USER}
      POSTGRES_PASSWORD: ${PASSWORD}

  backend:
    build:
      context: ./back/spe-con
      dockerfile: Dockerfile.${RAILS_ENV}
    volumes:
      - ./back/spe-con:/rails
    ports:
      - "3000:3000"
      
    depends_on:
      - db
    environment:
      DATABASE_URL: postgres://${USER}:${PASSWORD}@db/${DB}
  
    tty: true
    stdin_open: true

  frontend:
    build:
      context: ./front/spe-con
      dockerfile: Dockerfile.${NEXT_ENV}
    volumes:
      - ./front/spe-con:/app
      - /app/node_modules
      
 
    ports:
      - "8080:8080"
 

volumes:
  postgres_data:
ポイント

railsとnext.jsのポート番号は3000だが同じポート番号を使用すると競合が起きてコンテナを立ち上げられないので、 next.jsのポート番号を8080に設定します.

②環境毎に動的にdockerfileを切り替える Dockerfile.${RAILS_ENV}のように環境変数を用いて,開発環境なら開発環境のdockerfileを使用できるようにしています。 docker-compose コマンドのオプションでRAILS_ENV =devみたいにすることで動的に変更する

qiita.com

④フロントエンドとバックエンドをAPI連携

前提:バックエンドとフロントエンドのAPI連携とはcorsの設定なので.
そもそもcorsとは?となった方は下記を参照ください

loveenglish.hatenablog.com

全体像
  1. gem 'rack-cors'インストール.

  2. railsでcorsの設定.

1. gem 'rack-cors'インストール.

back/spe-con/gemfile すべての環境(テスト、開発、本番)に反映

gem 'rack-cors'

gemのインストール.

bundle install
railsでcorsの設定

config/initializers/cors.rb.
下記をコメントアウトを外します

さらに少し修正.

Rails.application.config.middleware.insert_before 0, Rack::Cors do
  allow do
    origins "http://0.0.0.0:3000/" #ここにどこのオリジンからのをリクエストを許可するか記載

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

dodckerfileを再ビルド

 docker-compose build --no-cache

コンテナの起動

 docker-compose up 

⑤. 連携ができたか確認する

完成予想図

画面に"Hello World"を表示する

全体像
  1. コンテナに入る

  2. scaffoldコマンド(データベース、コントローラー、ルーティング)実行.

  3. テストデータをデータベースに格納.

1. コンテナに入る
SpeCon/ #⇦ここのディレクトリ(docker-compose.ymlファイルがあるディレクトリ)でコンテナに入るコマンド実行
│
├── back/
│ └── spe-con/
│ ├── .env 
│ └── (Railsプロジェクトのファイル群)
│
├── front/
│ └── spe-con/
│ └── (Next.jsプロジェクトのファイル群)
│
└── docker-compose.yml

railsのコンテナに入ります

docker compose exec コンテナ名 bash

コンテナ名は

version: '3'

services:
  db:#⇦コンテナ名
省略

  backend: #⇦コンテナ名
    build:
      context: ./back/spe-con
      dockerfile: Dockerfile.${RAILS_ENV}
省略

  frontend:#⇦コンテナ名
    build:
      context: ./front/spe-con
省略

私の場合railsはbackendと名付けているので

docker compose exec backend bash

でコンテナに入る

②. scaffoldコマンド(データベース、コントローラー、ルーティング)実行.

Memoというデータベース名を作成

bundle exec rails g scaffold Memo message:string 

bundle execとはgemfile.lockに基づいてコマンドを実行するという意味

bundle exec rails db:migrate

上記でマイグレーションを実行する

③ テストデータをデータベースに格納.

db/seeds.rb

Memo.create!(
  [
{message:"Hello World"}
]
)

↓サンプルデータをデータベースに格納

bundle exec rails db:seed

page.tsx(next.js)

'use client';

import React, { useEffect, useState } from 'react';

export default function Home() {
  // サーバーから取得したデータを保存するstate
  
  const [data, setData] = useState({ message: '' });
 

  // データを取得する関数
  const fetchData = async () => {
      const response = await fetch('https://localhost:3000/memos', {
        method: 'GET',
        headers: {
          'Content-Type': 'application/json',
        },
      });
      const result = await response.json();
      setData(result[0]); // データをstateに保存
  
    }

  // コンポーネントがマウントされたときにデータを取得
  useEffect(() => {
    fetchData();
  }, []);

  return (
    <div>

      {data && (
        <div>
          <h2>取得したデータ:</h2>
          <p>{data.message}</p>
        </div>
      )}
    </div>
  );
}

すると画面に"Hello World"と表示される