前書き
- 私の設定が間違っている場合ご指摘ください。
pc環境
ruby 3.4.1
rails 8.0.1
next.js 15.1.6
react 19.0.0
node.js 22.9.0
MacBook Air (M1, 2020)
全体像
railsとnext.jsのプロジェクトをサブモジュール化
railsの設定(データベース接続)
docker-compose.ymlファイル作成
フロントエンドとバックエンドをAPI連携
連携ができたか確認する
①railsとnext.jsのプロジェクトをサブモジュール化
② railsの設定(データベース接続)
全体像
①環境変数を定義するファイル「.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*
またローカルの環境変数名と.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みたいにすることで動的に変更する
④フロントエンドとバックエンドをAPI連携
前提:バックエンドとフロントエンドのAPI連携とはcorsの設定なので.
そもそもcorsとは?となった方は下記を参照ください
全体像
gem 'rack-cors'インストール.
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"を表示する
全体像
コンテナに入る
scaffoldコマンド(データベース、コントローラー、ルーティング)実行.
テストデータをデータベースに格納.
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"と表示される