Ruby on Rails+Nuxt.jsの環境をDockerで作成するための手順メモ。
環境構築とAPI実装&呼び出し方法について。
開発環境
- MacOS Ventura(バージョン13.5)
- Docker Compose version v2.20.2-desktop.1
- Ruby 3.2.0
- Rails 7.0.7
- PostgreSQL 12.16
- Node 16.15.1
- Nuxt.js 2.15.8
ディレクトリとファイルを作成
以下のディレクトリ構成でファイルを作成します。
MyApp
├─ web
│  ├─ Dockerfile
│  ├─ Gemfile
│  └─ Gemfile.lock
├─ front
│  └─ Dockerfile
├─ docker-compose.yml
└─ .git# -----------------------------------
# Ruby on Rails環境構築用のDockerfile
# -----------------------------------
# ベースにするイメージ
FROM ruby:3.2.0
# RailsのインストールやDBへの接続に必要なパッケージをインストール(今回はPostgreSQLを使用する)
RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs postgresql-client
# コンテナ内にアプリ用のディレクトリを作成
RUN mkdir /MyApp
# 作成したディレクトリを作業用ディレクトリとして設定
WORKDIR /MyApp
# ローカルのGemfileとGemfile.lockをコンテナに配置
ADD Gemfile /MyApp/Gemfile
ADD Gemfile.lock /MyApp/Gemfile.lock
# コンテナ内にコピーしたGemfileのbundle install
RUN bundle install
# ローカルのファイルをコンテナに配置
COPY . /MyAppsource 'https://rubygems.org'
gem 'rails', '~> 7.0.7', '>= 7.0.7.2'(空ファイル)# -----------------------------------
# Nuxt.js環境構築用のDockerfile
# -----------------------------------
# ベースにするイメージ
FROM node:16-alpine3.14
# 作業用ディレクトリ
WORKDIR /var/www/html
# 必要なパッケージをインストール
RUN apk add --update \
    bash \
    curl
RUN npm update -g npm
# ネットワーク設定
EXPOSE 3000
ENV HOST 0.0.0.0version: '3'
services:
  # PostgreSQL用のコンテナ
  db:
    # ベースとなるイメージ
    image: postgres:12-alpine
    # 環境変数
    environment:
      - POSTGRES_USER=user
      - POSTGRES_PASSWORD=password
    # ローカル側のポート番号:コンテナ側のポート番号
    ports:
      - 5432:5432
    # ボリューム(永続的に保存したいデータ)
    # * 保存したいディレクトリをマウントする方法
    #   「- ローカル側の同期させたいディレクトリ:コンテナ側の同期させたいディレクトリ」
    # * 名前付きボリュームを利用する方法
    #   「- ボリューム名:コンテナ側の保存させたいディレクトリ」
    #   (ボリューム名を末尾のvolumes(services等と同じ階層に定義)で指定する)
    volumes:
      - postgres_data:/var/lib/postgresql/data
  # Ruby on Rails用のコンテナ
  web:
    # 指定したディレクトリにあるDockerfileを使ってビルドする
    build: ./web
    # コンテナ起動時に実行されるコマンド
    # (起動していた場合は停止後に)rails serverを起動する
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    # ボリューム(永続的に保存したいデータ)
    volumes:
      - ./web:/MyApp
    # ローカル側のポート番号:コンテナ側のポート番号
    ports:
      - "3000:3000"
    # dbコンテナ起動後にwebコンテナを起動する
    depends_on:
      - db
  # Nuxt.js用のコンテナ
  nuxt:
    build: ./front
    command: bash -c "cd MyApp && yarn dev"
    volumes:
      - ./front:/var/www/html
    # web側とポートが被るので3001に変更
    ports:
      - "3001:3000"
    tty: true
volumes:
  postgres_data:Docker操作コマンド
Dockerを操作するにはdocker-compose.ymlファイルがあるフォルダで以下のコマンドを実行します。
# イメージ作成
docker-compose build
# コンテナ作成
docker-compose create
# コンテナ起動
docker-compose start
# イメージ作成+コンテナ作成+コンテナ起動をまとめて実行
docker-compose up -d
# イメージ作成+コンテナ作成+コンテナ起動をまとめて実行(指定したサービスだけ起動)
docker-compose run [サービス名]
# 起動と同時にコマンド実行
docker-compose run [サービス名] [コマンド]
# コンテナ停止
docker-compose down
# コンテナの稼働状況を確認
docker-compose ps
# 起動中のコンテナでコマンド実行
docker-compose exec [サービス名] [コマンド]Ruby on Railsプロジェクトを新規作成
以下のコマンドを実行してRuby on Railsのプロジェクトを新規作成します。
# コンテナが起動済みの場合は"run" -> "exec"で読み替える
# (フロント側もまとめて全体で管理したいのでここではgit管理の対象外としておく)
docker-compose run web rails new . --force --database=postgresql --skip-bundle --skip-git
 -> 追加されたファイルがローカル環境にも同期して作成される
# Gemfileが更新されているので、イメージを再作成
docker-compose build続いて、データベースを作成します。
default: &default
  adapter: postgresql
  encoding: unicode
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: user
  password: password
  host: db
development:
  <<: *default
  database: MyApp_development
test:
  <<: *default
  database: MyApp_test
production:
  <<: *default
  database: MyApp_production
  username: <%= ENV["POSTGRES_USER"] %>
  password: <%= ENV["POSTGRES_PASSWORD"] %># データベースを作成
docker-compose exec web rails db:createhttp://localhost:3000にアクセスして、以下の画面が表示されればOK。

APIの実装
コントローラクラスを作成して、ルーティングを設定します。
# コントローラを作成
docker-compose exec -it web bash
# 以下、Dockerコンテナでの操作
rails g controller samples
cd app/controllers
mkdir api
cp samples_controller.rb api/module Api
    class SamplesController < ApplicationController
        # CSRFエラー対策
        skip_before_action :verify_authenticity_token
        # サンプルデータを返す
        def sample
            render json: { status: 'SUCCESS', message: 'Get sample data', data: { sample: 'hogehoge' } }
        end
    end
endRails.application.routes.draw do
  namespace :api do
    get "samples" => "samples#sample"
  end
end# 動作確認
curl http://localhost:3000/api/samples
 -> {"status":"SUCCESS","message":"Get sample data","data":{"sample":"hogehoge"}}Nuxt.jsプロジェクトを新規作成
以下のコマンドを実行してNuxt.jsのプロジェクトを新規作成します。
# Dockerコンテナのシェルを起動
docker-compose exec -it nuxt sh
# 以下、Dockerコンテナでの操作
npx create-nuxt-app MyApp
もしくは
yarn create nuxt-app MyApp
# インストール時の設定はお好みで
? Project name: MyApp
? Programing language: TypeScript
? Package manager: Yarn
? UI framework: Buefy
? Template engine: Pug
? Nuxt.js modules: o Axios, x PWA, x Nuxt/Content
? Linting tools: o ESLint, o Prettier, x Lint staged files, x Styleling, x Commitlint
? Testing framework: Jest
? Rendering mode: Single Page App
? Deployment target: Server
? Development tools: x
? Continuous integration: None
? Version control system: None *全体でGit使うのでここでは指定しない
# 起動
cd MyApp
yarn devhttp://localhost:3001にアクセスして、以下の画面が表示されればOK。
※UI FrameworkでBuefy以外を選んだ場合は見た目は違うものになります。

API呼出し処理の実装
プロキシを設定します。
// Dockerコンテナから見たホストマシンのIPアドレスを取得(プロキシ設定用)
const { execSync } = require('child_process')
let hostIp = execSync("cat /etc/hosts | awk 'END{print $1}' | sed -e 's/[0-9]\+$/1/g'")
// 改行を削除して、IPアドレスの最後のセグメントを1にする(なぜか上記コマンドでできない・・・)
hostIp = String(hostIp).replace('\r', '').replace('\n', '').replace(/[0-9]+$/, '1')
export default {
  〜略〜
  modules: [
    '@nuxtjs/axios',
    '@nuxtjs/proxy',
  ],
  axios: {
    baseURL: '/',
  },
  proxy: {
    '/api': {
      target: 'http://' + hostIp + ':3000/'
    }
  },
  telemetry: false,
  〜略〜
}画面を作成します。
<template>
    <div>
      <p>{{ sampleData.sample }}</p>
    </div>
</template>
<script>
export default {
    data: () => ({
        sampleData: ''
    }),
    created: function() {
        this.$axios.get('/api/samples')
        .then((res) => {
            this.sampleData = res.data.data
        })
        .catch((error) => {
            console.log(error)
        }
    }
}
</script>http://localhost:3001/sampleにアクセスして、Rails側で設定した値(hogehoge)が表示されていれば成功です。

 
  
  
  
  

コメント
database.ymlを下記にしないとdocker-compose exec web rails db:createが失敗しますかと
・username: MyApp→user
hikariさん
ご指摘ありがとうございます。修正しました。