Rails 升級到 7.1, ruby 升級到 3.3.4
by Aaron • 12/25/2024, 6:21:12 PM

最近產品開發的進度比時程來的快一些, 想當然在工程師的事件只有準時做完和需要多一點時間做完, 沒有提早做完這件事, 讓我可以偷一點點時間可以對產品進行一些升級與優化。
Notice: 這不是教學, 而是升級過程的 murmur
現況
- ruby: 2.7.8
根據 官方 maintenance status 可以看到 3.0 以前的 ruby 版本都已經 eol 了
eol (end-of-life): Branch is not supported by the ruby-core team any longer and does not receive any fixes. No further patch release will be released.
至於其他版本
Ruby 3.4
status: normal maintenance
release date: 2024-12-25
normal maintenance until: TBD
EOL: TBD
Ruby 3.3
status: normal maintenance
release date: 2023-12-25
normal maintenance until: TBD
EOL: 2027-03-31 (expected)
Ruby 3.2
status: normal maintenance
release date: 2022-12-25
normal maintenance until: TBD
EOL: 2026-03-31 (expected)
Ruby 3.1
status: security maintenance
release date: 2021-12-25
normal maintenance until: 2024-04-01
EOL: 2025-03-31 (expected)
- rails: 6.1.6.1 根據這個 compatibility table 這也是個 eol 的版本 …
Ruby Version | Required Ruby Version | Recommended Ruby Version |
---|---|---|
8.0.Z | >= 3.2.0 | 3.3 |
7.2.Z | >= 3.1.0 | 3.3 |
7.1.Z | >= 2.7.0 | 3.2.Z |
7.0.Z | >= 2.7.0 | 3.1.Z |
7.0.0 | >= 2.7.0 < 3.1 | 3.0.Z |
6.1.Z | >= 2.5.0 | 3.0.Z |
看起來低標應該是 rails 7.1, ruby 3.2
Separation of positional and keyword arguments
詳細可以看官方文件, 差異有點大… 不過最主要需要更改的的是 arguments 的部分, 測試覆蓋率如果不高的話會有點難過
def foo(a, b = 2, *args, c: 3, **kwargs)
pp a
pp b
pp args
pp c
pp kwargs
end
foo(1, 2, 3, {c: 4, d: 5})
# ruby 2.7
# 1
# 2
# [3]
# 4
# {:d=>5}
# ruby 3
# 1
# 2
# [3, {:c=>4, :d=>5}]
# 3
# {}
File.exist? and File.exists?
這個在 ruby 3.2 被更改了… 但這個比較好查找, 以下這行就可以解決了
grep -r "File.exists?" $(bundle show --paths)
升級跟 ruby 3 不相容的 gem
這個有很多工具可以自動幫你檢查哪些不相容, 但是… 應該能升的 gem 都升上去看看好了
- 最痛苦的: Faker 整個 interface 都改變了, 測試又很多, 這邊就只是體力活
結果一路升到了 ruby 3.3.4
升級 rails 版本
看了一下官方升級指南, 改動其實蠻多的, 不過條列得很清楚, 應該可以順利吧?
-
rails app:update
這要仔細看 diff, neovim 也有需多 plugin 可以很容易的更新 config files -
Zeitwerk
在之前如果有些 class name 不想要 nest 太多層, 例如 errors 相關的, 我們可能會
# /libs/errors/errors.rb
module Errors
class FooError < CustomError; end
class BarError < CustomError; end
end
# others
raise Errors::FooError
但是這違反命名規則
解法
# config/initializers/zeitwerk.rb
SUBDOMAINS = [
]
Rails.autoloaders.each do |autoloader|
SUBDOMAINS.each do |sub|
autoloader.ignore(Rails.root.join(sub))
end
end
rails_event_store
- 這按照升級指令的話會生成 5 個 migration file, 部分是不能 rollback 的, 需要自己寫 rollback 的反向 sql, 不然沒辦法切 branch 回去開發
- event_store_events 整張表照道理來說會蠻大的, 這個生成的 migration file 其實蠻危險的, 畢竟更改表的結構, 需要做好 migration plan
class CreatedAtPrecision < ActiveRecord::Migration[4.2]
def up
#...
end
def down
change_column :event_store_events, :created_at, :datetime, precision: nil
change_column :event_store_events_in_streams, :created_at, :datetime, precision: nil
end
end
class NoGlobalStreamEntries < ActiveRecord::Migration[4.2]
def up
#...
end
def down
remove_index :event_store_events, :event_id
execute "ALTER TABLE event_store_events DROP PRIMARY KEY, MODIFY id INT NOT NULL"
remove_column :event_store_events, :id
rename_column :event_store_events, :event_id, :id
execute "ALTER TABLE event_store_events ADD PRIMARY KEY (id)"
end
end
class AddForeignKeyOnEventIdToEventStoreEventsInStreams < ActiveRecord::Migration[7.0]
def up
# ...
end
def down
remove_foreign_key :event_store_events_in_streams, column: :event_id if foreign_key_exists?(:event_store_events_in_streams, :event_store_events, column: :event_id)
end
end
最後
內容減少了許多痛苦的過程, 最深刻的感想是寫測試很重要!!!