Upgrade Ruby from 3.0 to 3.2
升级 Ruby 到 3.2
Now that Ruby 3.3 preview 2 has been released, I've been working on upgrading a 3.0 project to 3.2. I've encountered a few problems with upgrading from 3.0 to 3.2, so I'm going to try to organize them here, and hopefully they'll help.
Bundled gems
In Ruby 3.1, some libs went from being standard libraries to bundled gems, such as net-ftp, which I use in my projects, and libraries like matrix. The list can be seen at Ruby 3.1.0 Released, scroll down to the "Standard libraries updates" section.
This means that if we're using bundlers, we need to add gems like matrix to our Gemfile, otherwise we'll run into this problem:
Rails `require': cannot load such file -- matrix
By the way, there are some differences between bundled gems and default libraries.
In the case of matrix, for example, in Ruby 3.1, matrix
has been changed from being part of the Ruby standard library to being a bundled gem. This change does not mean that it has been removed from Ruby's default libraries, but rather that matrix is now considered a gem.
bundled gems: these libs are now treated as gems, and we need to include them in our Gemfile when creating a new Ruby project using the bundler, but as bundled gems we don't need to install them individually, they are
default libraries: these libraries are still provided in the standard library when installing Ruby, i.e. we can still access them when using pure Ruby.
Psych (YAML) Security Updates
There have been some breaking changes in the behavior of YAML's load
and load_file
methods, mainly in the underlying Psych library.
A YAML.load
that used to work correctly may now throw this error:
YAML.load "--- !ruby/object:Matrix\nrows:\n- - 25\n - 93\n- - -1\n - 66\ncolumn_count: 2\n"
Psych::DisallowedClass:
Tried to load unspecified class: Matrix
This is because YAML.load
now calls Psych.safe_load
, which restricts the kinds of Ruby objects that are safe when parsing yaml.
The workaround is as follows:
if you trust your data then replace
YAML.load
withYAML.unsafe_load
If you don't trust the content of your data, then you need to add the permited_classes parameter, as follows:
YAML.load "--- !ruby/object:Matrix\nrows:\n- - 25\n - 93\n- - -1\n - 66\ncolumn_count: 2\n", permitted_classes: [Matrix]
=> Matrix[[25, 93], [-1, 66]]
In a Rails project, you can also configure config/application.rb
as follows:
config.after_initialize do
ActiveRecord.yaml_column_permitted_classes += [Date, Time, ActiveSupport::HashWithIndifferentAccess]
end
The context of this change can be seen here: [CVE-2022-32224] Possible RCE escalation bug with Serialized Columns in Active Record
Deprecating methods that are finally removed after a long time
The method File.exists?
was marked as Deprecating since Ruby 2.1, but it didn't say when it would be removed. After upgrading to Ruby 3.2, I encountered the error undefined method 'exists?' for File:Class
, and realized that it had finally been removed. Also removed was the Dir.exists?
method. See the "Removed methods" section in the release notes.
However, after searching the project globally and replacing File.exists?
with File.exist?
, I still get a similar error. This is because in the chef script (I copied and pasted from the Internet), there is also a usage of FileTest.exists?
.
I then checked that the test methods File.exists?
or File.file?
are acutally defined in the FileTest
module, which was included by the File class, and Ruby allows us to call these methods directly from FileTest. Therefore, the use of FileTest.exists?
needs to be changed to FileTest.exists?
.