Hegwin.Me

The bitterest tears shed over graves are for words left unsaid and deeds left undone.

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:

  1. if you trust your data then replace YAML.load with YAML.unsafe_load

  2. 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?.

< Back