【簡易アプリ】Rails6.1から7.1へのバージョンアップ

## バージョンアップ前の環境(Mac)
- Rails6.1
- Ruby3.0.6
- Node16
- Heroku-stuck20
## バージョンアップ後の環境
- Rails7.1
- Ruby3.3.0
- Node18
- Heroku-stuck24

## 1.バックアップの作成
作業を開始する前に、必ずバックアップを取ってください。これは任意のデータ損失を避けるために重要です。

## 2.Rubyのバージョンアップ
Ruby 3.0.6から安定版の`3.3.0`にバージョンアップします。rbenvを使用してバージョンアップを行いますが、Windowsの場合は、アンインストール後に再インストールが推奨されます。
```bash
rbenv install 3.3.0
rbenv local 3.3.0
rbenv global 3.3.0
rbenv rehash
ruby -v　# Ruby 3.3.0が表示されればOK
```

## 3.Rails7.1のインストール
GemfileでRailsのバージョンを更新します。
```diff_ruby
# Gemfile
- gem 'rails', '~> 6.1.7', '>= 6.1.7.7'
+ gem 'rails', '~> 7.1', '>= 7.1.3.4'
```
その後、以下のコマンドを実行します。
```bash
gem install rails -v 7.1.3.4
bundle update rails
bundle install
```

## 4. 設定ファイルと新機能の統合
Rails7には新しい設定や機能が多数含まれています。`rails app:update`コマンドを使用して、新しいデフォルト設定を取り入れます。

```bash
rails app:update
```
**エラー発生時の対処**
Pumaのバージョンが古く、Rack3と互換性がない場合、以下のようにPumaをバージョン6以上に更新します。
    
```diff_ruby
# Gemfile
- gem 'puma', '~> 5.0'
+ gem 'puma', '~> 6.0'
``` 
```bash
bundle update puma
rails app:update
```
**新しいマイグレーションファイルが追加された場合**
`rails app:update`実行後、新しいマイグレーションファイルが生成される場合があります。その場合、`ActiveRecord::PendingMigrationError`が発生するのでマイグレートします。
```
rails db:migrate
```
## 5. メソッドやコードの修正
Railsの[アップグレードガイド](https://railsguides.jp/upgrading_ruby_on_rails.html)に従い、必要に応じてアプリケーションのコードを修正します。
以下は変更点の一部です。

### button_toメソッドの変更
Rails 7.0では、button_toヘルパーメソッドが、永続化されているActive Recordオブジェクトを使用する際にデフォルトでPATCHリクエストを使用するように変更されました。ただし、method: :deleteなどのオプションを明示的に指定している既存のコードは変更不要です。
**修正が必要なケース**
```erb
<%= button_to 'Update Workshop', workshop_path(@workshop) %>
```
**修正後のコード**

```erb
<%= button_to 'Update Workshop', workshop_path(@workshop), method: :patch %>
```

## 6.Webpackからの移行とJavaScript/CSSの再構成
Rails7では、Webpackを使用しない新しい標準が導入されています。これに伴い、`importmap-rails`や`jsbundling-rails`を使用してJavaScriptの管理を行い、`cssbundling-rails`でCSSを管理します。これらの変更は、Node.jsに依存しないものではありますが、特定のツール（例えばesbuild）を使用する場合はNode.jsが必要になります。
`esbuild`は非常に高速で、大規模なJavaScriptコードベースのコンパイルに適しているため、ここでは引き続きNode.jsを使用します。
### Rails6とRsils7のディレクトリ構成の違い
Rails6からRails7への移行でディレクトリ構成に変化が見られます。Rails6では、Webpackerを用いたJavaScriptの管理が一般的でしたが、**Rails7ではWebpackerが廃止され、JavaScriptの管理方法が変更されています**。具体的には、Rails7では`jsbundling-rails`を使用してJavaScriptを直接app/javascript/ディレクトリ下で管理し、CSSも`cssbundling-rails`を介してapp/stylesheets/ディレクトリで扱うようになりました。
#### Rails6                              
- app/assets/                                
    -  stylesheets/                            
    -  javascripts/                                
- app/javascript/                              
    - packs/     
:::note
app/javascript/packs/ (Webpacker エントリーポイント) 
:::
#### Rails7
- app/assets/
    └── (主に画像や静的ファイルが格納される)
- app/javascript/
    └── (直接管理されるJavaScriptファイル)
:::note
app/stylesheets/ (CSS Bundlingによる管理)
:::
        
### importmap-rails、jsbundling-railsのインストール
では、ここからWebpackerを剥がし、JavaScriptの管理へと移行していきます。
Gemfileで`importmap-rails`、`jsbundling-rails`のインストールし、不要なgemを削除します。
```diff_ruby
# Gemfile
- gem 'webpacker', '5.4.3’
+ gem 'importmap-rails'
+ gem 'jsbundling-rails'
```
```bash
bundle install
rails javascript:install:esbuild
```
### Node.jsのバージョンアップ
Rails7でのJavaScriptビルドツールとして`esbuild`を使用するには、Node.jsのバージョンを更新する必要があります。以下のコマンドでNode.jsをバージョン18にアップグレードします。nvmを使用しない場合は、ローカルで再インストールをしましょう。
```bash
nvm install 18
nvm use 18
```
バージョン18が既にインストールされている場合は、nvm use 18を実行するだけでOKです。
### package.jsonの更新
Node.jsのバージョンアップ後は、`package.json`のenginesセクションを更新し、不要な依存関係を削除します。
```json
  "engines": {
    "node": "18.20.4"
  }
```
Webpack関連の依存関係を削除し、新しいビルドスクリプトを設定します。
```diff_json
- "@rails/webpacker": "5.4.3"
- "webpack": "4.46.0"
- "webpack-cli": "3.3.12"
```
↓自分の場合
```json
 "scripts": {
  "build": "esbuild app/javascript/*.* --bundle --sourcemap --format=esm --outdir=app/assets/builds --public-path=/assets --loader:.ttf=file",
  "build:css": "esbuild app/javascript/stylesheets/*.scss --bundle --sourcemap --loader:.scss=css --outdir=app/assets/builds --public-path=/assets",
  "start": "esbuild app/javascript/*.* --bundle --sourcemap --format=esm --outdir=app/assets/builds --public-path=/assets --watch"
}
```
## JavaScriptファイルの再配置とCSSの統合
Rails7の導入により、プロジェクトのディレクトリ構造を更新し、JavaScriptとCSSの管理方法を最新の標準に合わせます。
### JavaScriptファイルの再配置
/app/javascript/packs ディレクトリに配置されているJavaScriptファイルを、新しいディレクトリ構造に合わせて移動します。
1. /app/javascript/packs 内のファイルを **/app/javascript**に移動
1. application.js の相対パスを ../ から **./** に変更(1の変更があった場合)
1. Webpacker関連のコード（environment.js、application.js など）を削除
    1. `const { environment } = require('@rails/webpacker');`こういうのもし書いていれば
1. 以下のように application.scss ファイルを編集して、他のスタイルシート（SCSSファイル）をインポート
    1. 再利用性とパフォーマンスを高めます

```js
// app/javascript/stylesheets/application.scss
@import "./hello.scss";
@import "./tweet.scss";
@import "./users.scss";
```

### CSSの統合とビルド
Rails7では`cssbundling-rails`を利用してCSSを効率的に管理します。app/assets/stylesheets から **app/javascript/stylesheets**にCSSファイルを移行し、ビルドします。
1. コメントは `/* ... */` 形式で統一する。例: /* Hello component style */
    1. SCSSファイルで`//`でコメントしているとエラーになります
1. esbuild を使用してSCSSファイルをCSSに変換するための設定を確認
```json
 "scripts": {
  "build:css": "esbuild app/javascript/stylesheets/*.scss --bundle --sourcemap --loader:.scss=css --outdir=app/assets/builds --public-path=/assets"
}
```
ビルドコマンドを実行
```bash
npm run build:css
```
ビルドが成功したことを確認した後、CSSが適切に適用されているかウェブページを通じて確認します。

#### 統合とエラー解決
もし`NoMethodError`または`Sprockets::DoubleLinkError`が発生した場合、以下の解決策を試してください.

- stylesheet_pack_tag は Rails7.0以降非推奨です。stylesheet_link_tag を使用してCSSを読み込んでください。
```
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbo-track': 'reload' %>
```
- link_directory メソッドが正しいディレクトリを指しているか 
    - `app/assets/config/manifest.js`を確認
```js
//= link_tree ../images
//= link_directory ../../javascript/stylesheets .css
//= link_directory ../builds .css
//= link_directory ../builds .js
```
## 後書き
今回、Rails 6.1からRails 7.1へのバージョンアップの過程をご紹介しました。今回のアップグレードでは、WebpackerからImportmapやjsbundling-railsへの移行により、JavaScriptの管理が大きく変化しました。
この記事が、実際のプロジェクトへのRailsアップグレードに役立つことを願っています。また、環境設定やディレクトリ構造の変更によって新たな問題に直面した場合でも、この記事が一助となれば幸いです。