7
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Ruby 2.6、Rails 5.2 からの Ruby 3、Rails 7 へのバージョンアップ

Last updated at Posted at 2022-10-17

Herokuで稼働させていたRailsアプリケーションが Heroku-18 のEOLを間近に控えてバージョンアップを余儀なくされたので対応内容を後世のために記しておきます。

アプリケーションの構成概要

Ruby: 2.6.3
Rails: 5.1.7

DB: PostgreSQL
開発環境: Mac、Windows
本番環境: Heroku (Heroku-18)

なお、Railsは APIモード で実行しています。

[config/application.rb]
config.api_only = true

経緯

Herokuのstackの Heroku-18 が来年の2023年5月1日でデプロイが行えなくなります。
当初は1つ上の Heroku-20 への対応を検討していたのですが2年後にまた Heroku-22 対応するのはしんどいので一気に Heroku-22 に上げることを検討しました。

Heroku-22 に必要なもの

Ruby: 3系 (デフォルトは3.1.x)

Rubyを3系に上げるにはRailsも含め、主要なgemのバージョンアップが必須でした。
以下はバージョンアップを行ったgemの一覧。

変更後のバージョン

Ruby: 3.1.2
Rails: 7.0.4

gemの変更差分

gem 変更前 変更後
bundler 1.17.3 2.3.23
pg 1.1.4 1.4.4
nokogiri 1.10.3 1.12.5
msgpack 1.3.0 1.5.6
bootsnap 1.4.4 1.12.0
active_model_serializers 0.10.9 0.10.13
activerecord-import 1.0.4 1.4.1
rspec-rails 3.8.2 5.1.2
pry-byebug 3.7.0 3.10.1
timecop 0.9.1 0.9.5

以下は Ruby 3、および Rails 7 での仕様変更、実装変更へのコードレベルでの対応になります。

1. Ruby 3 対応

大文字の予約語を小文字にする

Ruby 3 では命名規約が厳密に適用されるようで予約語を誤って大文字で記述していたものがエラーになりました。
これはRailsのDBマイグレーションスクリプトで真偽値の false を誤って FALSE と記述していたものがエラーになった例です。

[db/migrate/YYYYMMDD_create_hoge.rb]
NameError: uninitialized constant CreateHoge::FALSE

      t.boolean :fuga_flg, default: FALSE

命名規約エラー

クラス名、モジュール名はキャメルケースで記述するルールですが Ruby 2.x では以下のような命名が許容されていました。

HTMLGenerator

しかし、Ruby 3.x では読込時にエラーになります。
これはRailsで開発時は動的な読込で気付かなかったのに本番環境に上げたら引っかかるというパターンが多そうです。

Unable to load application: NameError: uninitialized constant HTMLGenerator

このケースでは HtmlGenerator などにリネームする必要があります。

SQL、HTML、XMLなどアッパーケースで記述される技術要素などを含むクラス、モジュールがこれに引っかかりやすそうです。

キーワード引数の分離

キーワード引数の分離に関しては多くの記事で言及されているので内容自体は触れません。
以下のリンク先などを参照してください。

プロと読み解く Ruby 3.0 NEWS - キーワード引数の分離

基本的には Hash で渡していたものをキーワード引数に置き換える作業になります。

2. Rails 7 対応

トランザクションブロックで return すると commit されない

Rails 7 ではDBのトランザクションブロックで return すると commit が実行されずに rollback されます。
return を除き、ifブロックに置き換えるなどの対処が必要です。

ActiveRecord::Base.transaction do
  # 前略

  return if hoge_condition

  # 後略
end

index_exists? の実装変更

特殊なパターンでハマったのが ActiveRecord が提供している index_exists? メソッドの実装変更。
3番目の引数のオプション設定の定義が変わっているのでHashで渡していたものはエラーになりました。

  • Rails 5.x
def index_exists?(table_name, column_name, options = {})
  # 略
end
  • Rails 7.x
def index_exists?(table_name, column_name, **options)
  # 略
end
index_exists?(:hoge, :column_a, { name: 'hoge_index1' })

⇒ ArgumentError: wrong number of arguments (given 3, expected 2)

Rails のセッション管理の仕様変更への対応

APIモードで実行していると Rails 6.x からは以下のエラーが発生するようになり、リクエストが処理させません。

Your application has sessions disabled. To write to the session you must first configure a session store

Rails の API モードでセッションを有効にする

上記の記事を参考に config/application.rb 内で細工を施してやり過ごしました。

config.api_only = true

# Rails 6 からのセッション周りの仕様変更への対応ハック
config.middleware.use(ActionDispatch::Cookies)
config.middleware.use(ActionDispatch::Session::CookieStore)
config.middleware.use(ActionDispatch::ContentSecurityPolicy::Middleware)
7
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?