Rails Guide をやるために Rails6.1 の環境を作ろうとしたら思いの外苦戦したので備忘を含めて記事にします。
なぜRailsのバージョンが6.1なのかというと、パーフェクトRuby on Rails のバージョンが6.0.3なのでなるべく6系に合わせたかったというのと、6.1がLTSバージョンだからです。
結論だけ知りたい人向け
結論に飛ぶか下のリンクを参考にしてください。
環境
- ホストOS:Windows 11 23H2
- ゲストOS:Ubuntu 20.04.5
- Docker version:20.10.12
- Docker Compose version:2.10.2
- Ruby:3.0.5
- Ruby on Rails:6.1
- MariaDB:10.11
基本パターン
まずは普通にイメージを作ってコンテナを作成していきます。
ディレクトリ構成
$ tree --dirsfirst
.
├── src
│ ├── Gemfile
│ └── Gemfile.lock
├── .env
├── Dockerfile
└── docker-compose.yml
.env
UID=1000
GID=1000
USERNAME=docker
GROUPNAME=docker
Gemfile
source 'https://rubygems.org'
gem 'rails', '6.1.0'
Gemfile.lockは空ファイルになります。
Dockerfile
FROM ruby:3.0.5
# Node.jsをインストール
RUN curl -sL https://deb.nodesource.com/setup_20.x | bash - && apt-get install -y nodejs
# yarnパッケージ管理ツールをインストール
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
&& echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
&& apt-get update -qq && apt-get install -y yarn
COPY ./src /app
ARG USERNAME=docker
ARG GROUPNAME=docker
ARG UID=1000
ARG GID=1000
RUN groupadd -g ${GID} ${GROUPNAME}
RUN useradd -u ${UID} -g ${GID} -s /bin/bash -m ${USERNAME}
RUN gpasswd -a ${USERNAME} sudo
USER ${USERNAME}
WORKDIR /home/${USERNAME}/app
COPY --chown=${USERNAME}:${GROUPNAME} ./src /home/${USERNAME}/app
RUN bundle config --local set path 'vendor/bundle' \
&& bundle install
EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]
・13行目 ~ 21行目
WSL2特有の問題だったと思うのですが、ユーザーを作らずにそのままコンテナでコマンドを実行すると、 root ユーザーでログインしてしまいます。その場合、 rails new
や rails generate
で作成されるファイルの所有者がすべて root になってしまって編集できなくなります。それを避けるために一般ユーザーを作成して、ログインユーザーを一般ユーザーに切り替える必要があります。
・24行目
上記で作成したユーザの権限でディレクトリをコピーしないと、 bundle install
実行時に permission denied でエラーになってしまいます。
docker-compose.yml
version: '3'
services:
db:
image: mariadb:10.11
command: --default-authentication-plugin=mysql_native_password
volumes:
- mysql-data:/var/lib/mysql
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: password
TZ: "Asia/Tokyo"
web:
build:
context: .
args:
- UID=${UID}
- GID=${GID}
- USERNAME=${USERNAME}
- GROUPNAME = ${GROUPNAME}
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
user: "${UID}:${GID}"
volumes:
- ./src:/home/${USERNAME}/app
ports:
- "3000:3000"
depends_on:
- db
environment:
DATABASE_PASSWORD: password
TZ: "Asia/Tokyo"
volumes:
mysql-data:
driver: local
基本的には他の記事と同じだと思いますが、タイムゾーンを東京に変更しています。
イメージのビルド
$ docker-compose build
プロジェクトの作成
$ docker-compose run --rm web rails new . --force --database=mysql
プロジェクト作成時のログに、警告が山ほど出てきます。大丈夫なのかと言われれれば大丈夫ではありません。とりあえず今回は先に進めます。
イメージの再ビルド
$ docker-compose build
今の状態だとイメージに bundle install
ができていないので、再度イメージをビルドしてやります。
データベースの設定・作成
default: &default
adapter: mysql2
encoding: utf8mb4
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root
password: <%= ENV.fetch("DATABASE_PASSWORD") %>
host: db
データベースのコンフィグで password
と host
を変更します。
$ docker-compose run --rm web rails db:create
コンテナの起動
$ docker-compose up
問題点
この状態でもブラウザで「http://localhost:3000/」にアクセスすればトップページにアクセスできます。

では何が問題なのかというと、今の状態だとJavaScriptが効きません。私はこの問題でRails Guideの「6.5 記事を削除する」でlink_toのmethod: :deleteがGetになる問題が発生し、無駄に時間を使ってしまいました。ちなみにこの問題はググれば解決方法が出てきますが、今回の問題はそれ以前の問題です。
原因
この問題の原因は、webpackerがコンパイルできてないことにあります。試しにコンパイルするとエラーが出ます。
$ docker-compose run --rm web rails webpacker:compile
(省略)
ERROR in ./app/javascript/packs/application.js
Module build failed (from ./node_modules/babel-loader/lib/index.js):
Error: Cannot find package '@babel/plugin-proposal-private-methods' imported from /home/docker/app/babel-virtual-resolve-base.js
...
(省略)
簡単に言えば「 @babel/plugin-proposal-private-methods
パッケージが見つかりません」ってことですね。
修正
では @babel/plugin-proposal-private-methods
をインストールすればいいと思うかもしれませんが、そうではありません。現在、 @babel/plugin-proposal-private-methods
は名前が変更されていて、今は @babel/plugin-transform-methods
に変更されています。しかもこれだけではなく、 @babel/plugin-proposal-*
系はすべて @babel/plugin-transform-*
に変更されています。
この情報だけだと変更しないといけないパッケージが網羅できていないので、Webpackerの設定ファイル( babel.config.js
)を見ていきます。
[
'@babel/plugin-proposal-class-properties',
{
loose: true
}
],
[
'@babel/plugin-proposal-object-rest-spread',
{
useBuiltIns: true
}
],
[
'@babel/plugin-proposal-private-methods',
{
loose: true
}
],
[
'@babel/plugin-proposal-private-property-in-object',
{
loose: true
}
],
設定ファイルを見ると @babel/plugin-proposal-class-properties
, @babel/plugin-proposal-object-rest-spread
, @babel/plugin-proposal-private-methods
, @babel/plugin-proposal-private-property-in-object
があるので、@babel/plugin-transform-class-properties
, @babel/plugin-transform-object-rest-spread
, @babel/plugin-transform-private-methods
, @babel/plugin-transform-private-property-in-object
をインストールして、設定ファイルを書き換える必要があります。
ついでに @babel/core
のバージョンが古いという警告が出るので、@babel/core
のバージョンも上げておきます。
パッケージのインストール
$ docker-compose run --rm web yarn add @babel/core@latest --dev
$ docker-compose run --rm web yarn add @babel/plugin-transform-class-properties @babel/plugin-transform-object-rest-spread @babel/plugin-transform-private-methods @babel/plugin-transform-private-property-in-object --dev
babel.config.js
[
'@babel/plugin-transform-class-properties',
{
loose: true
}
],
[
'@babel/plugin-transform-object-rest-spread',
{
useBuiltIns: true
}
],
[
'@babel/plugin-transform-private-methods',
{
loose: true
}
],
[
'@babel/plugin-transform-private-property-in-object',
{
loose: true
}
],
Webpackerのコンパイル
この状態でもう一度Webpackerをコンパイルしてやります。
$ docker-compose run --rm web rails webpacker:compile
(省略)
Compiling...
Compilation failed:
Error: error:0308010C:digital envelope routines::unsupported
...
(省略)
またエラーが出ました。これはNode.js のバージョンと OpenSSL の互換性の問題から発生するようです。
Node v17.0.0以降では「OpenSSL 1.1.1」に替わって「OpenSSL 3.0」が収録されるようになっています。プロジェクトで使っているあるライブラリが、サポートしていないOpenSSLのバージョンを使っているということでエラーになっているみたいです。Node.jsが暗号化関連の操作(ハッシュ関数など)を行おうとしたとき、その操作がサポートされていないということになるようです。
これを解決するには環境変数で NODE_OPTIONS: --openssl-legacy-provider
を設定して、OpenSSL3をレガシープロパイダーに戻すことで対応します。
docker-compose.yml
docker-compose.yml
を編集して環境変数を設定します。
version: '3'
services:
db:
image: mariadb:10.11
command: --default-authentication-plugin=mysql_native_password
volumes:
- mysql-data:/var/lib/mysql
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: password
TZ: "Asia/Tokyo"
web:
build:
context: .
args:
- UID=${UID}
- GID=${GID}
- USERNAME=${USERNAME}
- GROUPNAME = ${GROUPNAME}
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
user: "${UID}:${GID}"
volumes:
- ./src:/home/${USERNAME}/app
ports:
- "3000:3000"
depends_on:
- db
environment:
NODE_OPTIONS: --openssl-legacy-provider
DATABASE_PASSWORD: password
TZ: "Asia/Tokyo"
volumes:
mysql-data:
driver: local
Webpackerのコンパイル
$ docker-compose run --rm web rails webpacker:compile
これでWebpackerがコンパイルできて、JavaScriptが使えるようになりました。
結論
今までの操作を踏まえて、 Dockerfile や手順を修正します。
.env
UID=1000
GID=1000
USERNAME=docker
GROUPNAME=docker
Gemfile
source 'https://rubygems.org'
gem 'rails', '6.1.0'
Gemfile は変更なし。
Dockerfile
FROM ruby:3.0.5
# Node.jsをインストール
RUN curl -sL https://deb.nodesource.com/setup_20.x | bash - && apt-get install -y nodejs
# yarnパッケージ管理ツールをインストール
RUN curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | apt-key add - \
&& echo "deb https://dl.yarnpkg.com/debian/ stable main" | tee /etc/apt/sources.list.d/yarn.list \
&& apt-get update -qq && apt-get install -y yarn
COPY ./src /app
ARG USERNAME=docker
ARG GROUPNAME=docker
ARG UID=1000
ARG GID=1000
RUN groupadd -g ${GID} ${GROUPNAME}
RUN useradd -u ${UID} -g ${GID} -s /bin/bash -m ${USERNAME}
RUN gpasswd -a ${USERNAME} sudo
USER ${USERNAME}
WORKDIR /home/${USERNAME}/app
COPY --chown=${USERNAME}:${GROUPNAME} ./src /home/${USERNAME}/app
RUN bundle config --local set path 'vendor/bundle' \
&& bundle install
RUN yarn add @babel/core@latest --dev \
&& yarn add @babel/plugin-transform-class-properties @babel/plugin-transform-object-rest-spread @babel/plugin-transform-private-methods @babel/plugin-transform-private-property-in-object --dev
EXPOSE 3000
CMD ["rails", "server", "-b", "0.0.0.0"]
・29行目 ~ 30行目
@babel/plugin-transform-*
をインストールする手順を追加しています。
docker-compose.yml
version: '3'
services:
db:
image: mariadb:10.11
command: --default-authentication-plugin=mysql_native_password
volumes:
- mysql-data:/var/lib/mysql
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: password
TZ: "Asia/Tokyo"
web:
build:
context: .
args:
- UID=${UID}
- GID=${GID}
- USERNAME=${USERNAME}
- GROUPNAME = ${GROUPNAME}
command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
user: "${UID}:${GID}"
volumes:
- ./src:/home/${USERNAME}/app
ports:
- "3000:3000"
depends_on:
- db
environment:
NODE_OPTIONS: --openssl-legacy-provider
DATABASE_PASSWORD: password
TZ: "Asia/Tokyo"
volumes:
mysql-data:
driver: local
・31行目
環境変数 NODE_OPTIONS=--openssl-legacy-provider
を設定する手順を追加しています。
イメージのビルド
$ docker-compose build
プロジェクトの作成
$ docker-compose run --rm web rails new . --force --database=mysql
イメージの再ビルド
$ docker-compose build
データベースの設定・作成
default: &default
adapter: mysql2
encoding: utf8mb4
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root
password: <%= ENV.fetch("DATABASE_PASSWORD") %>
host: db
$ docker-compose run --rm web rails db:create
Webpacker設定の修正
plugins: [
'babel-plugin-macros',
'@babel/plugin-syntax-dynamic-import',
isTestEnv && 'babel-plugin-dynamic-import-node',
'@babel/plugin-transform-destructuring',
[
'@babel/plugin-transform-class-properties',
{
loose: true
}
],
[
'@babel/plugin-transform-object-rest-spread',
{
useBuiltIns: true
}
],
[
'@babel/plugin-transform-private-methods',
{
loose: true
}
],
[
'@babel/plugin-transform-private-property-in-object',
{
loose: true
}
],
[
'@babel/plugin-transform-runtime',
{
helpers: false
}
],
[
'@babel/plugin-transform-regenerator',
{
async: false
}
]
].filter(Boolean)
基本パターンにはなかった追加した手順です。@babel/plugin-proposal-*
を @babel/plugin-transform-*
に変更します。
Webpackerのコンパイルは適宜自動で実行されるのでここでする必要はありません。
コンテナの起動
$ docker-compose up
ブラウザから http://localhost:3000/ にアクセスして、Railsのトップページが表示されれば成功です。

コメント