Next.js + Ruby on Rails(APIモード) on Docker 構築手順
Next.jsでフロントエンド、Ruby on RailsのAPIモードでバックエンドを構成するアプリケーションの開発環境をDocker上で構築する方法をまとめておきます。Railsで作成したAPIをフロントで表示する手順と、Next.jsをTypeScriptに対応させる方法も合わせて紹介します。
Dockerはインストールされている前提で説明を始めます。
今回用いたDockerのバージョンは以下の通りです。
docker version : 20.10.5
docker-compose version : 1.29.0
1. Dockerの準備
ファイル構成
以下の構成でファイルを作成します。
|--front/
| |--Dockerfile
|--api/
| |--Dockerfile
| |--Gemfile
| |--Gemfile.lock #空ファイル
|--docker-compose.yml
docker-compose.ymlの記述
version: '3.7'
services:
db:
image: mysql:5.7
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: sample
MYSQL_PASSWORD: password
ports:
- 4306:3306
volumes:
- mysql-db:/var/lib/mysql
api:
tty: true
depends_on:
- db
build:
context: ./api/
dockerfile: Dockerfile
ports:
- 3000:3000
volumes:
- ./api:/app
command: rails server -b 0.0.0.0
front:
build:
context: ./front/
dockerfile: Dockerfile
volumes:
- ./front/app:/usr/src/app
command: 'yarn dev'
ports:
- "8000:3000"
volumes:
mysql-db:
driver: local
フロント側Dockerfileの記述
FROM node:14-alpine
WORKDIR /usr/src/app
サーバー側Dockerfileの記述
FROM ruby:2.7
ENV LANG=C.UTF-8 \
TZ=Asia/Tokyo
WORKDIR /app
RUN apt-get update -qq && apt-get install -y nodejs default-mysql-client
COPY Gemfile /app/Gemfile
COPY Gemfile.lock /app/Gemfile.lock
RUN bundle install
# Start the main process.
CMD ["rails", "server", "-b", "0.0.0.0"]
Gemfileの記述
source 'https://rubygems.org'
gem 'rails', '~> 6.0.3', '>= 6.0.3.2'
上記ファイルが準備できたらビルドします。
$ docker-compose build
2. Next.jsアプリを作成する
yarn createでfrontディレクトリに作成します。
$ docker-compose run --rm front yarn create next-app .
アプリの生成が完了したら、起動してみます。
$ docker-compose up
localhost:8000にアクセスして、以下の画面が表示されていればNext.jsアプリの作成はOKです! 👏
3. Ruby on Railsでサーバー環境を構築する
続いて、RailsをAPIモードで立ち上げます。今回、データベースはMySQLを採用しました。
まず、apiディレクトリにRailsアプリを作成します。
$ docker-compose run --rm api bundle exec rails new . --api -d mysql
生成途中で、Gemfileのコンフリクトが生じますが、Y
を入力して進めてください。
アプリケーションの作成が完了したら、database.yml
を変更します。
docker-compose.ymlに記述したデータベース設定に合わせてください。
# MySQL. Versions 5.5.8 and up are supported.
・・・
default: &default
adapter: mysql2
encoding: utf8mb4
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root
+ password: password
- host: locaohost
+ host: db
development:
<<: *default
- database: app_development
+ database: sample
・・・
Railsアプリを起動させます。
$ docker-compose up --build
localhost:3000にアクセスして、以下の画面が表示されていればRailsアプリの作成はOKです! 👏
4. JSONを返すAPIを作成する
Next.jsで用いるAPIをRailsで作成しましょう。
$ docker-compose run --rm api bundle exec rails g scaffold post title:string
各種ファイルが生成されます。
$ docker-compose run --rm api bundle exec rails db:migrate
postsテーブルが作成されます。
seedの機能を用いて雑に初期データを取り込みます。
Post.create!(
[
{
title: 'Next.js + Ruby on Rails + Docker の環境構築'
},
{
title: 'React Hooks でカスタムフックを作る'
},
{
title: 'GraphQL と Apollo Client 入門'
},
{
title: '【TypeScript4.3】Template Literal Types'
},
{
title: 'Tailwind CSS でダークモード実装'
},
]
)
記述したテストデータをテーブルに取り込みます。
$ docker-compose run --rm api bundle exec rails db:seed
localhost:3000/posts
にアクセスし、以下のようなJSONデータが確認できればOKです。
5. Next.jsでAPIから取得したデータを画面に表示する
Rails側の環境設定でホストを指定する
fetchする際に、localhost:3000
ではNext.js側でエラーが発生するため、Rails側で設定を追加する必要があります。
Rails.application.configure do
・・・
+ # localhost:3000では通信に失敗するためhostをdocker-compose.ymlのコンテナ名に合わせる
+ config.hosts << "api"
end
index.jsでAPIを受け取り、表示する
では、いよいよNext.js側でデータを表示させます。
const Home = (props) => {
return (
<div>
<h2>
POSTの一覧
</h2>
<table>
{props.posts.map((post) =>
<tr>
<td>{post.id}.</td>
<td>{post.title}</td>
</tr>
)}
</table>
</div>
)
}
export const getStaticProps = async () => {
// URLはlocalhostではなくapiとなる
const response = await fetch("http://api:3000/posts", {method: "GET"});
const json = await response.json();
return {
props: {
posts: json
},
};
}
export default Home;
docker-compose up
でdockerを起動後、localhost:8000
にアクセスし、以下のようにデータが表示されていれば完了です! 🥳
6. Next.jsアプリにTypeScriptを導入する
最後に、フロントエンド開発のベストプラクティスとしてデファクト化したTypeScriptの環境を構築して終了しようと思います。
インストール
必要パッケージをインストールします。
$ docker-compose run --rm front yarn add --dev typescript @types/node @types/react @types/react-dom
拡張子の変更
以下 js(jsx)
ファイルを ts(tsx)
ファイルに変更します。
- ./pages/_app.js -> ./pages/_app.tsx
- ./pages/index.js -> ./pages/index.tsx
- ./pages/api/hello.js -> ./pages/api/hello.ts
各ファイルをTypeScript仕様に書き換える
import React from 'react'
import {AppProps} from 'next/app';
import '../styles/globals.css';
const MyApp = ({ Component, pageProps }: AppProps) => {
return <Component {...pageProps} />
}
export default MyApp
import React, { FC } from "react";
import { GetStaticProps } from "next";
type Post = {
id: number;
title: string;
}
type Props = {
posts: Post[];
}
const Home: FC<Props> = (props) => {
return (
<div>
<h2>POSTの一覧</h2>
<table>
{props.posts.map((post) =>
<tr>
<td>{post.id}.</td>
<td>{post.title}</td>
</tr>
)}
</table>
</div>
)
}
export const getStaticProps: GetStaticProps = async context => {
const response = await fetch("http://api:3000/posts", {method: "GET"});
const json = await response.json();
return {
props: {
posts: json
},
};
}
export default Home;
以上でTypeScriptでの開発環境が整いました。
ちなみに、package.json
には以下の記述の記述が追加されています。
"devDependencies": {
"@types/node": "^14.14.37",
"@types/react": "^17.0.3",
"@types/react-dom": "^17.0.3",
"typescript": "^4.2.4"
}
以上です!! 🥳
ぜひ参考にしてみてください。
Discussion
たくみさんの記事で無事railsで環境構築ができました!!
めちゃめちゃ助かりました!
超超ありがとうございました!!
ありがとうございます!!
お役に立ててとても嬉しいです 🥳