Rails6系から7系へのアップグレード方法

# 背景
Rails6系はActive SupportとSecurity Supportが切れています。早急にRails7系にアップグレードする必要があがります。

https://endoflife.date/rails

しかしながら、Rails6系からRails7系へのバージョンアップはメジャーバージョンアップということもあり、細かな設定の変更に時間がかかりました。

そこで本記事では、効率的なバージョンアップを実現できるように、僕自身のアップグレード方法を記録として残します。アプグレードしたWebアプリは、「Touringmate」です。

https://site.drive-mate.net/

開発中のアプリによっては、追加でGemのアップデートが必要になるかもしれませんが、参考になれば嬉しいです。

※2024年12月現在で安定版であるRails7.2.2は、Ruby3.1.0以上を必要とします。Rubyのアップグレードをお忘れなく！

# バージョン
Ruby:3.2.4
Rails:6.1.7.7→7.2.2
bundler:2.5.3
node:22.11.0
npm:10.9.0
yarn:4.0.0
webpack:5.96.1
shakapacker:8.0.0

# 開発環境
macOS: Sonoma14.7.1
エディター: Cursor@VSCode

# Rails6系から7系へのアップグレード手順
## 1. Gemの更新
Gemfile内のRailsのバージョンを更新します。

~~~
#Gemfile
gem "rails", "~> 7.2.0"

#ターミナル
bundle update rails
~~~

## 2. JavaScriptパッケージの更新
package.json内のRails関連パッケージを最新バージョンに更新します。

package.jsonを確認したところ、「@rails/actioncable」「@rails/activestorage」「@rails/ujs」がバージョンアップ対象でした。

以下のコードで最新バージョンに更新します。

~~~
yarn up "@rails/actioncable@latest"
yarn up "@rails/activestorage@latest"
yarn up "@rails/ujs@latest"
~~~

また、Webアプリのフロントエンドを一部Reactで実装しているため、「react」と「react-dom」も最新バージョンに更新します。

~~~
yarn up react@latest
yarn up react-dom@latest
~~~

念のため、全体の依存関係を再インストールします。

~~~
yarn install
~~~

## 3. オートローダーのClassicモードからZeitwerkモードへの移行
Rails 6からRails 7にアップグレードする際、オートローダーをClassicモードからZeitwerkモードに移行します。

config/application.rbファイルに「config.load_defaults 7.0」を追加します。
~~~
# config/application.rb
module DriveMate1
  class Application < Rails::Application
    config.load_defaults 7.0
~~~
config/environments/development.rbで以下の設定を確認または追加し、自動読み込みが有効であることを確認します。
~~~
# config/environments/development.rb
config.file_watcher = ActiveSupport::EventedFileUpdateChecker
~~~

## 4. Devise関連のアップデート
WebアプリでDeviseを使用している場合は、関連のgemを最新バージョンに更新します。

僕の場合は「Devise」「Devise Token Auth」「OmniAuth」が対象でした。

### 4-1. Deviseの更新
ターミナルで「bundle update devise」を実行、Deviseのバージョンを4.9.4に更新しました。

~~~
# ターミナル
bundle update devise
~~~

### 4-2. Devise Token Authの更新
Rails7のDevise Token Authは、GitHub上でサポートされています。したがって、GitHubリポジトリから直接Devise Token Authをインストールするように設定します。

https://stackoverflow.com/questions/71062789/error-using-devise-token-auth-gem-rails-7/71088408

~~~
# Gemfile
gem 'devise_token_auth', github: 'lynndylanhurley/devise_token_auth'

# ターミナル
bundle install
~~~

### 4-3. OmniAuthの更新
OmniAuthのバージョン2.0以上は、Ruby 3.0+をサポートしています。OmniAuthのバージョンを2.0以上に更新します。

## 5. listen gemの追加
「rails s」でサーバーを立ち上げようとした結果、「listen is not part of the bundle」というエラーが発生しました。

以下のコードで、listen gemを追加します。

~~~
# Gemfile
gem 'listen', '~> 3.7'

# ターミナル
bundle install
~~~

# React構成箇所の反映
Shakapacker導入済みのRails6系を7系にバージョンアップする場合、以下のエラーが発生するかもしれません。

~~~
Uncaught TypeError: __webpack_require__(...).start is not a function
    at ./app/javascript/application.js (application.js:6:1)
    at __webpack_require__ (bootstrap:19:1)
    at __webpack_exec__ (Touring_group_list.js:141:1)
    at Touring_group_list.js:141:1
    at __webpack_require__.O (chunk loaded:25:1)
    at Touring_group_list.js:141:1
    at webpackJsonpCallback (jsonp chunk loading:36:1)
    at application.js:1:73
~~~
config/webpack/webpack.config.js（またはconfig/webpack/environment.js）に、React用Babelローダーを設定します。
~~~
# config/webpack/webpack.config.js
module: {
    rules: [
      {
        test: /\.jsx?$/, // .js または .jsx ファイルを対象
        exclude: /node_modules/, // node_modules ディレクトリは除外
        use: {
          loader: 'babel-loader', // Babelローダーを使用
          options: {
            presets: ['@babel/preset-env', '@babel/preset-react'], // React用プリセットを指定
            plugins: [isDevelopment && 'react-refresh/babel'].filter(Boolean), // 開発環境でFast Refresh有効化
          },
        },
      },
    ],
  },
~~~

以下のパッケージがインストールされているかを確認します。

・@babel/core
・@babel/preset-env
・@babel/preset-react
・babel-loader
  
インストールされていない場合は、以下のコードを実行して、インストールします。
~~~
yarn add @babel/core @babel/preset-env @babel/preset-react babel-loader
~~~

app>javascript?application.jsファイルの「require("@rails/ujs").start()」でエラーが発生するかもしれません。

その場合は、「require("@rails/ujs").start()」を以下のコードに書き換えます。
~~~
# app>javascript>application.js
import Rails from "@rails/ujs"
Rails.start()
~~~

@rails/ujsのバージョンが古い場合は、以下のコードで最新バージョンに更新します。
~~~
yarn add @rails/ujs@latest
~~~

なお、Rails7から利用可能となった「Turbo Drive」を有効化すると、React構築箇所が画面に反映されないかもしれません。
（画面をリロードすると、React構築箇所が画面に反映されます）

これは、「Turbo Drive」による画面読み込みの高速化（Reactコンポーネントの読み込み遅延）が原因と考えられます。

したがって、app>javascript?application.jsファイルでは、「@hotwired/turbo-rails」をインポートしてはいますが、「Turbo.session.drive = false;」で「Turbo Drive」も無効化しています。

~~~
# app>javascript>application.js
import "@hotwired/turbo-rails";
// Turbo Driveを無効化
Turbo.session.drive = false;
~~~

# ActiveSupport::Deprecation.warnへの対処
「rails s」でサーバーが立ち上がったは良いものの、「ActiveSupport::Deprecation.warn」というエラーが頻繁に発生しました。

Rails7.2.2では、「ActiveSupport::Deprecation.warn」メソッドが削除されたためにエラーが発生します。

以下に僕が直面した「ActiveSupport::Deprecation.warn」への対処方法をまとめます。

## ActiveSupport::Deprecation.warnの置き換え
Rails 7.2以降では、独自のデプリケーションオブジェクトを使用する必要があります。

config>initializers>deprecation.rbファイルを作成、以下をコーディングします。
~~~
# config>initializers>deprecation.rb
# 独自のデプリケーションオブジェクトを作成
MyAppDeprecator = ActiveSupport::Deprecation.new('2.0', 'MyApp')

# 警告を出す
MyAppDeprecator.warn('このメソッドは非推奨です。')
~~~

## CarrierWaveに対する対処
### 「fog_provider=': private method warn' called for ActiveSupport::Deprecation:Class (NoMethodError)」というエラーが発生しました。

carrierwave.rbファイルから、以下のコードを削除しました。

~~~
# config.fog_provider = 'fog/aws'
~~~

### 「private method 'warn' called for ActiveSupport::Deprecation:Class」というエラーが発生しました。

以下のコードで、CarrierWaveを最新バージョンに更新しました。
~~~
# Gemfile
gem 'carrierwave', '~> 3.1.0.beta'

# ターミナル
bundle update carrierwave
~~~

## web_consoleに対する対処
### 「web_console_permissions': private method warn' called for ActiveSupport::Deprecation:Class (NoMethodError)」というエラーが発生しました。

web_consoleを最新バージョンに更新しました。

~~~
# Gemfile
gem 'web-console', '~> 4.2.1'

# ターミナル
bundle update web-console
~~~

# まとめ
本記事では、Rails6系から7系へのアップグレード手順について、詳細に解説しました。

Rails7系は新機能の追加により、より強固で高性能なフレームワークとなっていますが、アップグレードには多くのステップが必要です。特にGemやJavaScriptパッケージの更新、オートローダーの移行、React構成箇所の調整など、各段階でエラーや互換性の問題に対処する必要がありました。

また、Devise関連のGemやActiveSupport::Deprecation.warnの変更に対応することで、安定した動作環境を構築するための工夫も必要でした。これらの経験や手順が、読者の方々が効率的にアップグレードを進める際の参考になれば幸いです。

Railsのアップグレードは一度の作業で完結するものではなく、テストやデプロイ後も注意深く運用を続ける必要があります。本記事を通じて、アップグレードのプロセスがスムーズに進むことを願っています。