Rails6.1 -> Rails7のアップグレード
良い
new_framework_defaults_X_Y.rbは「アップデート移行措置のためのファイル」と捉えました。このファイルはアップデートのためのTODOリストとして使用し、完了後は削除
Rails7でHotwireが導入されてwebpackerがオプションになったし、地味に変更が多そうな予感...。先人たちの失敗を参考にしつつ基本通りにアップデートしていく。
テスト
既存のテストが通ることを一応確認。
code:example.sh
RAILS_ENV=test rspec ./spec
gemのアップデート
まずは基本のgemのアップデート。Gemfileのgem 'rails'だけバージョンを固定して指定する。
やはりネイティブエクステンション周りが鬼門かな...
code:example.sh
bundle update
よく起きる問題
mini_racerのupgradeができない
案の定である。2022年にもなってmini_racerのビルドがコケて嵌ってる人間俺だけか?
BUNDLE_FORCE_RUBY_PLATFORM=1をつけてbundle updateすることでソースコードビルドにしてみる。nokogiriとかも対象になってしまうのでクッソ時間かかる...
2.0.0からsprocketsに依存しなくなっている。アップデートしてしまえば問題なさそう。
他にも内部的に使ってたわ...
ということでmini_racerはbundle updateせず既存のバージョンを固定で指定するようにしておく。base imageのgccとかの問題でlibv8-nodeがうまくbuildできないみたいな話の可能性もありめんどくさそうなので。
0.5.0でlibv8-nodeのバージョンが変わっている。なんかこの辺りっぽい。
imageとvolumeを全部消して--no-cacheをつけて再試行したらアップデートできた。
が、pumaを起動しようとしたら死んだ。やはりダメじゃん
ということで0.4.0固定にして進む
Build Cacheデカすぎ
というかこのbuildの最中にNo space leftのエラーが出てしまった。docker system dfしたらBuild Cacheが20GB以上あった。docker builder pruneで削除。
PunditのDeprecation Warningを消す
include Punditをinclude Pundit::Authorizationに変える。
Rubocopのエラー解消
Layout/ArgumentAlignment: Use one level of indentation for arguments following the first line of a multi-line method call.
Layout/HashAlignment: Align the keys of a hash literal if they span more than one line
こんなコードがあったときにc\ dのように1文字だがスペースを含む場合は%記法はやめるように修正されたらしい
code:rb
ddtrace(Datadogのmigration)
0->1.0への移行。configの設定が変わっている。
pagyの移行
1,2,3,4,5のそれぞれのメジャーバージョンに対してBreaking Changeがあるのでそれみてやっていく。
Ruby 2.7.4 -> Ruby 3.1.2
rubyのアップデートもやる。Railsをアップデートするよりは軽いはず。適当にこの辺のqiitaとかで先人のハマりどころをみておいて、Dockerのイメージバージョンを3.1.2に変える。 rubygems 3.1.5 is not supported on 3.1.2. The oldest version supported by this ruby is 3.3.3
gem update --system 3.3.3 && gem update bundlerしたらrubygemsが対応してないので変更せよってやつ
2.7.4で更新したGemfile.lockのせいでDockerイメージを3.1.2に変更してbundle installが通らない
ホスト側のGemfile.lockを消して一旦通す
mini_racerがビルドできない
またしてもmini_racerとそのネイティブエクステンションのlibv8-node。どうもこのissueによるとbundlerを最新にしてmini_racerも最新にすればいけるっぽいと言ってる人がいた
0.4.0に固定して進んだが結局最新にすることになった
Rails couldn't infer whether you are using multiple databases from your database.yml and can't generate the tasks for the non-primary databases. If you'd like to use this feature, please simplify your ERB. Psych::BadAlias: Cannot load database configuration:
gemのpsych関連のエラーか
psychが4系で破壊的変更が入る。これによって4系ではエラーが発生する。YAML.loadとか結構根幹で使われてるコードが動かなくなるので厳しい。
gem 'psych', '~> 3.1'とかして3系で留めておくコードをGemfileに書くことで難を逃れるのが一旦は良さそう。
LoadError: cannot load such file -- net/smtp
Ruby3.1で消えたgemの影響
gem 'net-smtp', require: false を追加
rspec関連
ハッシュからキーワード引数への自動変換しないようになる非互換性に関するエラー
いわゆるこれ
code:rb
def hoge(a:, b:)
end
params = {a: 1, b: 2}
hoge(**params) #=> これならOK Railsのアップグレード
bundle update rails
RailsDiffをみながらファイルの変更に追従
ActiveSupport::Cacheの新しいシリアライズフォーマット
キャッシュがなくなっても問題なければ7.0にしちゃう
NoMethodError: undefined method `has_key?' for nil:NilClass
devise-two-factorがRails7に対応できてないっぽい?
attr_encryptedでRails7のActiveRecordで導入されたencrypted_attrbutesと名前が被ってしまっている。
とりあえずencryption用のsoltなどを生成してcredentialsに登録する
code:bash
# salt等を生成する
bin/rails db:encryption:init
# 追記する
EDITOR="vi" bin/rails credentials:edit
既存テーブルにotp_secretカラムを追加して既存のレコードをマイグレートする
code:migrate.rb
class MigrateOtpCodes < ActiveRecord::Migration7.0 def up
add_column :users, :otp_secret, :text
User.reset_column_information
User.where.not(encrypted_otp_secret: nil).find_each do |user|
user.update!(
otp_secret: Encryptor.decrypt(
Base64.decode64(user.encrypted_otp_secret),
key: <the encryption key you used for devise-two-factor>,
iv: user.encrypted_otp_secret_iv.unpack1('m'),
salt: user.encrypted_otp_secret_salt.slice(1..-1).unpack1('m')
)
)
end
end
def down
remove_column :users, :otp_secret
end
end