どうもこんにちは。
今回は、Claude Codeを使用して、Ruby/Railsのバージョンアップをやったお話を記事にします。
バージョンアップ前とバージョンアップ後の比較
以下のように、Ruby/Railsのバージョンアップを計画しました。
| 項目 | バージョンアップ前 | バージョンアップ後 |
|---|---|---|
| Ruby | 3.0.6 | 3.4.2 |
| Rails | 7.0.5 | 8.1.2 |
バージョンアップフロー
- 現在のバージョンで
Rubocop/Brakeman/RSpecの整備 - Rubyのバージョンを
3.0.6→3.3.6へバージョンアップ & Railsのバージョンを7.0.5→7.2.2 - Railsのバージョンを
7.1.2.3→8.0.1へバージョンアップ - Rubyのバージョンを
3.3.6→3.4.2へバージョンアップ - Railsのバージョンを
8.0.1→8.1.2へバージョンアップ
各ステップの想定工数(従来通り、AI使用なし)
| 順 | ○→● | 想定工数 |
|---|---|---|
| 1 |
Rubocop/Brakeman/RSpecの整備 |
10日 |
| 2 | Ruby 3.0.6→3.3.6, Rails 7.0.5→7.2.2
|
10日 |
| 3 | Rails 7.2.2→8.0.1
|
10日 |
| 4 | Ruby 3.3.6→3.4.2
|
10日 |
| 5 | Rails 8.0.1→8.1.2
|
3~5日 |
RSpecの整備を日頃からできていなかったので、3週間程度の工数をかける想定でした。
また、8.0.1→8.1.2については大きな変更がないと判断できたため、3~5日と短い工数となっています。
実際に費やした工数(Claude Codeを使用)
| 順 | ○→● | 工数 | 実際の日時 |
|---|---|---|---|
| 0 | Claude Codeによるバージョンアップ計画策定 | 5時間 | 1/30 13:00~18:00 |
| 1 |
Rubocop/Brakeman/RSpecの整備 |
5日 | 2/2~2/5 |
| 2 | Ruby 3.0.6→3.3.6, Rails 7.0.5→7.2.2
|
3時間 | 2/24 21:00 ~ 24:00 |
| 3 | Rails 7.1.2.3→8.0.1
|
2時間 | 2/25 1:00 ~ 3:00 |
| 4 | Ruby 3.3.6→3.4.2
|
2時間 | 2/25 3:00 ~ 5:00 |
| 5 | Rails 8.0.1→8.1.2
|
1時間 | 2/25 10:00 ~ 11:00 |
Rubocop/Brakeman/RSpecの整備に工数をかけましたが、バージョンアップ作業自体はほぼ1晩で完了しました。
バージョンアップの方法
Claude Codeでワークフローを作成して、それに沿ってエージェントがバージョンアップを実行するようにしました。
1. Ruby/Railsアップグレードガイドで差分を調査して方針を固める
差分の調査を行い、方針を固めます。もちろん、Claudeくんと一緒にソースコードや仕様を確認しながら行います。
2. ワークフローを作成
以下の記事で紹介している、CC Workflow StudioというVS拡張を使用して、以下のようなワークフローを作成しました。
Skillで以下のマークダウンの内容をコピー&ペーストして、AIさんにご自身のプロジェクトのバージョンや状態に合うようにリメイクして使用してください。
また、私が独自で作ったコード解析Skillが以下のワークフローSkillに登場しますが、必要に応じて削除してください。
Ruby 3.0.6→3.3.6 / Rails 7.0.5→7.2.2 (Skill名: version-up-phase1)
ステップ 1: 現在状態の確認
docker-compose exec web ruby -v
docker-compose exec web rails -v
cat .ruby-version
grep "ruby\|rails" Gemfile | head -10
ステップ 2: Gemfile の更新
以下の変更を行います:
# Rubyバージョン
ruby '3.3.6' # 3.0.6 → 3.3.6
# Railsバージョン
gem 'rails', '7.2.2' # 7.0.5 → 7.2.2
# テストライブラリ更新
gem 'web-console', '~> 4.0' # ~> 2.0 → ~> 4.0
gem 'rspec-rails', '~> 7.0' # ~> 4.0.0.beta2 → ~> 7.0
# セキュリティパッチ
gem 'delayed_job_active_record', '~> 4.1', '>= 4.1.10'
# ElasticBeanstalk固定バージョンをコメントアウト
# gem 'stringio', '3.0.1'
# gem 'nio4r', '2.7.1'
ステップ 3: .ruby-version の更新
3.3.6
ステップ 4: Dockerfile の更新
FROM ruby:3.3.6 # 3.0.6 → 3.3.6
RUN apt-get update -qq && apt-get install -y nodejs netcat ffmpeg
WORKDIR /sample
COPY Gemfile /sample/Gemfile
COPY Gemfile.lock /sample/Gemfile.lock
RUN gem install bundler -v '2.5.23' # 2.3.15 → 2.5.23
RUN bundle install
COPY . /sample
ステップ 5: config/application.rb の更新
config.load_defaults 7.2 # 7.0 → 7.2
ステップ 6: bundle update の実行
docker-compose exec web bundle update --conservative
エラーが発生した場合は依存関係の競合を解消してから続行します。
ステップ 7: Docker 環境の再構築
docker-compose down
docker-compose build --no-cache
docker-compose up -d
新しいRubyバージョンを確認:
docker-compose exec web ruby -v
docker-compose exec web rails -v
ステップ 8: DB の準備
docker-compose exec web rails db:migrate
docker-compose exec web rails db:test:prepare
ステップ 9: RuboCop の実行
run-rubocop スキルを実行します。
- 警告・エラーがある場合は修正してから次のステップへ進みます
-
run-rubocop-autofixスキルを使って自動修正を試みます - 自動修正できない場合は手動で修正します
ステップ 10: Brakeman の実行
run-brakeman スキルを実行します。
- セキュリティ警告がある場合は内容を確認し、必要に応じて修正します
- Ignore対応が適切な場合はBrakeman ignoreファイルに追加します
ステップ 11: RSpec(request spec)の実行
run-all-rspec スキルを実行します。
- テストが失敗した場合は原因を特定して修正します
ステップ 12: RSpec(model spec)の実行
run-model-rspec スキルを実行します。
- テストが失敗した場合は原因を特定して修正します
完了条件
以下がすべて満たされたらPhase 1完了です:
- RuboCop: 警告・エラーなし
- Brakeman: セキュリティ警告なし(または適切にIgnore済み)
- RSpec requests: 全テストパス(0 failures)
- RSpec models: 全テストパス(0 failures)
完了したら以下のコマンドで変更をコミットします:
git add Gemfile Gemfile.lock .ruby-version Dockerfile config/application.rb
git commit -m "Phase 1: Upgrade to Ruby 3.3.6 + Rails 7.2.2"
git push origin <current-branch>
Rails 7.1.2.3→8.0.1(Skill名: version-up-phase2)
前提条件
Phase 1(Ruby 3.3.6 + Rails 7.2.2)が完了済みであること。
docker-compose exec web ruby -v # ruby 3.3.6 であること
docker-compose exec web rails -v # Rails 7.2.2 であること
ステップ 1: Gemfile の更新
以下の変更を行います:
# Railsバージョンを更新
gem 'rails', '8.0.1' # 7.2.2 → 8.0.1
# Sprockets継続使用(Rails 8デフォルトのPropshaftは使わない)
gem 'sprockets-rails', require: 'sprockets/railtie'
ステップ 2: bundle update の実行
docker-compose exec web bundle update rails
エラーが発生した場合は依存関係の競合を解消してから続行します。
ステップ 3: rails app:update の実行
docker-compose exec web rails app:update
対話が発生した場合の対応方針:
-
dで差分を確認してから判断 - カスタマイズが重要な設定ファイルは
n(no) でスキップし、後で手動マージ - 新規ファイル(initializers等)は
Y(yes) で受け入れる
ステップ 4: config/application.rb の更新
config.load_defaults 8.0 # 7.2 → 8.0
# Sprockets継続
config.assets.enabled = true
ステップ 5: config/initializers/new_framework_defaults_8_0.rb の作成
# frozen_string_literal: true
# Rails 8.0の新しいデフォルト設定を確認・調整
# sanitizerは現在のHTML4を継続(sanitize gemとの互換性確保)
Rails.application.config.action_view.sanitizer_vendor = Rails::HTML4::Sanitizer
ステップ 6: Docker 環境の再構築
docker-compose down
docker-compose build --no-cache
docker-compose up -d
新しいRailsバージョンを確認:
docker-compose exec web rails -v
ステップ 7: DB の準備
docker-compose exec web rails db:migrate
docker-compose exec web rails db:test:prepare
ステップ 8: RuboCop の実行
run-rubocop スキルを実行します。
- 警告・エラーがある場合は修正してから次のステップへ進みます
-
run-rubocop-autofixスキルを使って自動修正を試みます - 自動修正できない場合は手動で修正します
ステップ 9: Brakeman の実行
run-brakeman スキルを実行します。
- セキュリティ警告がある場合は内容を確認し、必要に応じて修正します
- Ignore対応が適切な場合はBrakeman ignoreファイルに追加します
ステップ 10: RSpec(request spec)の実行
run-all-rspec スキルを実行します。
- テストが失敗した場合は原因を特定して修正します
ステップ 11: RSpec(model spec)の実行
run-model-rspec スキルを実行します。
- テストが失敗した場合は原因を特定して修正します
$$## 完了条件
以下がすべて満たされたらPhase 2完了です:
- RuboCop: 警告・エラーなし
- Brakeman: セキュリティ警告なし(または適切にIgnore済み)
- RSpec requests: 全テストパス(0 failures)
- RSpec models: 全テストパス(0 failures)
完了したら以下のコマンドで変更をコミットします:
git add Gemfile Gemfile.lock config/application.rb config/initializers/new_framework_defaults_8_0.rb
git commit -m "Phase 2: Upgrade to Rails 8.0.1"
git push origin <current-branch>
Rails 8.0 主要な変更点と対策
Sprockets vs Propshaft
Rails 8.0 のデフォルトは Propshaft ですが、本プロジェクトでは Sprockets を継続使用します。
sprockets-rails gem を Gemfile に追加して対応します。
非推奨メソッドの削除
Rails 7.2 で非推奨だったメソッドが Rails 8.0 で削除されています。
テスト実行時にエラーが出た場合は代替メソッドに置き換えてください。
config.load_defaults 8.0 の変更
# 新しいデフォルト値の主な変更
# - Action Cable: async adapter がデフォルト
# - Active Storage: サービス設定の変更
Ruby 3.3.6→3.4.2(Skill名: version-up-phase3)
前提条件
Phase 2(Ruby 3.3.6 + Rails 8.0.1)が完了済みであること。
docker-compose exec web ruby -v # ruby 3.3.6 であること
docker-compose exec web rails -v # Rails 8.0.1 であること
ステップ 1: Gemfile の更新
以下の変更を行います:
# Rubyバージョンを更新
ruby '3.4.2' # 3.3.6 → 3.4.2
ステップ 2: .ruby-version の更新
3.4.2
ステップ 3: Dockerfile の更新
FROM ruby:3.4.2 # 3.3.6 → 3.4.2
RUN apt-get update -qq && apt-get install -y nodejs netcat ffmpeg
WORKDIR /sample
COPY Gemfile /sample/Gemfile
COPY Gemfile.lock /sample/Gemfile.lock
RUN gem install bundler -v '2.6.2' # 2.5.23 → 2.6.2(最新版)
RUN bundle install
COPY . /sample
ステップ 4: Docker 環境の再構築
docker-compose down
docker-compose build --no-cache
docker-compose up -d
新しいRubyバージョンを確認:
docker-compose exec web ruby -v # ruby 3.4.2 であること
ステップ 5: Gem の再インストール確認
docker-compose exec web bundle install
docker-compose exec web bundle check
ステップ 6: DB の準備
docker-compose exec web rails db:migrate
docker-compose exec web rails db:test:prepare
ステップ 7: RuboCop の実行
run-rubocop スキルを実行します。
- 警告・エラーがある場合は修正してから次のステップへ進みます
-
run-rubocop-autofixスキルを使って自動修正を試みます - 自動修正できない場合は手動で修正します
ステップ 8: Brakeman の実行
run-brakeman スキルを実行します。
- セキュリティ警告がある場合は内容を確認し、必要に応じて修正します
- Ignore対応が適切な場合はBrakeman ignoreファイルに追加します
ステップ 9: RSpec(request spec)の実行
run-all-rspec スキルを実行します。
- テストが失敗した場合は原因を特定して修正します
ステップ 10: RSpec(model spec)の実行
run-model-rspec スキルを実行します。
- テストが失敗した場合は原因を特定して修正します
完了条件
以下がすべて満たされたらPhase 3完了です(PMN-631 全フェーズ完了):
- RuboCop: 警告・エラーなし
- Brakeman: セキュリティ警告なし(または適切にIgnore済み)
- RSpec requests: 全テストパス(0 failures)
- RSpec models: 全テストパス(0 failures)
完了したら以下のコマンドで変更をコミットします:
git add Gemfile Gemfile.lock .ruby-version Dockerfile
git commit -m "Phase 3: Upgrade to Ruby 3.4.2"
git push origin <current-branch>
Rails 8.0.1→8.1.2(Skill名: version-up-phase4)
前提条件
Phase 3(Ruby 3.4.2 + Rails 8.0.1)が完了済みであること。
docker-compose exec web ruby -v # ruby 3.4.2 であること
docker-compose exec web rails -v # Rails 8.0.1 であること
ステップ 1: Gemfile の更新
以下の変更を行います:
# Railsバージョンを更新
gem 'rails', '8.1.2' # 8.0.1 → 8.1.2
ステップ 2: bundle update の実行
docker-compose exec web bundle update rails
エラーが発生した場合は依存関係の競合を解消してから続行します。
ステップ 3: rails app:update の実行
docker-compose exec web rails app:update
対話が発生した場合の対応方針:
-
dで差分を確認してから判断 - カスタマイズが重要な設定ファイルは
n(no) でスキップし、後で手動マージ - 新規ファイル(initializers等)は
Y(yes) で受け入れる
ステップ 4: config/application.rb の更新
config.load_defaults 8.1 # 8.0 → 8.1
ステップ 5: config/initializers/new_framework_defaults_8_1.rb の作成
Rails 8.1 の新しいデフォルト設定を確認し、必要に応じて調整します。
# frozen_string_literal: true
# Rails 8.1 の to_time_preserves_timezone のデフォルトが :zone に変更された。
# config/initializers/to_time_preserves_timezone.rb でオプトアウト済みの場合は削除または更新すること。
また、config/initializers/to_time_preserves_timezone.rb が存在する場合は内容を確認し、
Rails 8.1 では config.active_support.to_time_preserves_timezone = :zone がデフォルトになるため、
明示的な設定が不要であれば削除します。
ステップ 6: fixture_path 非推奨警告の対応
Rails 7.1 から出ている以下の非推奨警告を解消します:
Rails 7.1 has deprecated the singular fixture_path in favour of an array.
spec/rails_helper.rb などで config.fixture_path を使用している場合は config.fixture_paths (複数形) に変更します:
# Before
config.fixture_path = Rails.root.join('spec/fixtures')
# After
config.fixture_paths = [Rails.root.join('spec/fixtures')]
ステップ 7: Docker 環境の再構築
docker-compose down
docker-compose build --no-cache
docker-compose up -d
新しいRailsバージョンを確認:
docker-compose exec web rails -v # Rails 8.1.2 であること
ステップ 8: DB の準備
docker-compose exec web rails db:migrate
docker-compose exec web rails db:test:prepare
ステップ 9: RuboCop の実行
run-rubocop スキルを実行します。
- 警告・エラーがある場合は修正してから次のステップへ進みます
-
run-rubocop-autofixスキルを使って自動修正を試みます - 自動修正できない場合は手動で修正します
-
注意:
params.expectへの自動変換はテスト失敗の原因になりやすいため、適用後にテストで検証すること
ステップ 10: Brakeman の実行
run-brakeman スキルを実行します。
- セキュリティ警告がある場合は内容を確認し、必要に応じて修正します
- Ignore対応が適切な場合はBrakeman ignoreファイルに追加します
ステップ 11: RSpec(request spec)の実行
run-all-rspec スキルを実行します。
- テストが失敗した場合は原因を特定して修正します
ステップ 12: RSpec(model spec)の実行
run-model-rspec スキルを実行します。
- テストが失敗した場合は原因を特定して修正します
完了条件
以下がすべて満たされたらPhase 4完了です:
- RuboCop: 警告・エラーなし
- Brakeman: セキュリティ警告なし(または適切にIgnore済み)
- RSpec requests: 全テストパス(0 failures)
- RSpec models: 全テストパス(0 failures)
完了したら以下のコマンドで変更をコミットします:
git add Gemfile Gemfile.lock config/application.rb
git commit -m "Phase 4: Upgrade to Rails 8.1.2"
git push origin <current-branch>
3. Planモードで各ワークフローを順に実行するように計画を立てる
version-up-phase1→version-up-phase4までを順に実行していくように、計画を立てます。
また、この段階でPhaseごとにブランチを分けるように指示しておくと良いです。
4. Auto AcceptモードでClaudeくんに処理を投げる
計画通りに進めてねって伝えればバージョンアップを実行してくれます。
まとめ
今まで辛かったバージョンアップがAIエージェントの手によって1晩で完了しました。
その分、アップグレードガイドなどで差分を調査し、注意が必要なものや不要なものなどの選別は先に行なっておく必要があります。
また、全体的に細かく試験を実施して、バージョンアップによるバグが発生していないかを確認しなければいけません。これは基本的にはE2Eテストで実行し、細かい部分については人間の手でテストするのが良いと思います。
テスト頑張ります。
以上