Skip to content

Upgrade Ruby (3.1.4 -> 3.3.8) & Rails (7.1.3 -> 7.2.2.1) #749

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 29 commits into
base: dev
Choose a base branch
from

Conversation

fosterfarrell9
Copy link
Collaborator

@fosterfarrell9 fosterfarrell9 commented Feb 22, 2025

Note: This PR has a "best before" date: 2025-03-31, see here. The respective Ruby on Rails upgrade guide is here.

This PR upgrades Ruby to 3.3.7 and Rails to 7.2.2.1 (and in particular resolves #611 and goes most of the way for #709), and some gems that needed an upgrade in order to make the Rails upgrade work. So far, it seems to work mostly nicely. Several deprecation warnings were shown; I fixed them all except one (see below),
and some unit tests are failing (see below).

Important

For your local setup to still work after this PR, perform the steps outlined here in the wiki.
Furthermore, since we are changing the Docker base image (FROM), you have to rebuild all MaMpf Docker Containers from scratch.

Notes for the reviewer:

  • I let the app:update script overwrite our puma.rb file which seemed quite out of date compared to the current standard one. One notable difference is the handling of the pid file. Before, it was
ENV.fetch("PIDFILE") { "tmp/pids/server.pid" }

Now, it is

# Specify the PID file. Defaults to tmp/pids/server.pid in development.
# In other environments, only set the PID file if requested.
pidfile ENV["PIDFILE"] if ENV["PIDFILE"]

On partiulcar, if we need the PID file in production, we should set an environment variable. I am not sure: We have

echo "Ensuring no stale server pid file is present"
rm -f tmp/pids/server.pid

in production/entrypoint_worker.sh.

  • We still have files related to a "development" environment (and if you search in our codebase, you will find several occurences of "development" referring to a "development" environment. Do we need that? All our development takes place in docker_development .
  • Rails 7.2 standard production.rb ccontains the line config.force_ssl = true. I added it, but put it in a comment. We should find out what happens if we uncomment it.
  • It appears that the standard in Rails 7.2 is that in a production console you can onbly see the id of database entries, nothing more. I overrode this in production.rb via
config.active_record.attributes_for_inspect = :all
  • In docker_development.rb I added the following lines wich come form the current Rails default devlopment file:
  # Raise error when a before_action's only/except options reference missing actions.
  config.action_controller.raise_on_missing_callback_actions = true

  # Apply autocorrection by RuboCop to files generated by `bin/rails generate`.
  # config.generators.apply_rubocop_autocorrect_after_generate!

I think the first one makes sense, and the second one should remain a comment since we have our own rubocop thing going on.

  • We still get this warning
DEPRECATION WARNING [legacy-js-api]: The legacy JS API is deprecated and will be removed in Dart Sass 2.0.0.
More info: https://sass-lang.com/d/legacy-js-api

See here. It appears we could get rid of it if we upgrade sass-loader to v16 in our yarn modules, but do we want that? It seems that vite offers a better solution, see here.

  • I am a little confused about the failing unit tests. The error messages say
Failure/Error:
  expect do
    UserCleaner.new.send_additional_warning_mails
  end.not_to have_enqueued_mail(UserCleanerMailer, :pending_deletion_email)

StandardError:
  To use HaveEnqueuedMail matcher set `ActiveJob::Base.queue_adapter = :test`

so this seems to refer to this. But in config/environments/test.rb we already set

config.active_job.queue_adapter = :test

Update: I guess the problem is in config/initializers/active_job.rb where we set (for all environments)

Rails.application.config.active_job.queue_adapter = :sidekiq

which probably overrides the :test setting. Do we have tests (unit or cypress) that rely on sidekiq? If not, we could just do a conditional here.

  • I checked the things mentioned in Upgrade to Rails 7.2 #611 and did not see any more deprecation warnings. Concerning the active_support.cache_format_version: I think we should be able to safely change this in production now (which happens automatically in this PR since we use the Rails 7.2 framework defaults in application.rb).

@fosterfarrell9 fosterfarrell9 changed the title Upgrade/ruby and rails Upgrade ruby and rails Feb 22, 2025
@Splines Splines changed the title Upgrade ruby and rails Upgrade Ruby to 3.3.7 and Rails to 7.2.2.1 May 2, 2025
@Splines Splines requested a deployment to testing-review May 2, 2025 15:03 — with GitHub Actions Waiting
# Any libraries that use a connection pool or another resource pool should
# be configured to provide at least as many connections as the number of
# threads. This includes Active Record's `pool` parameter in `database.yml`.
threads_count = ENV.fetch("RAILS_MAX_THREADS", 3)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the database.yml we still use a value of 5 instead of 3 here (in case that the env variable is not set, but we never set it anywhere). See also my comment on the respective Rails issue.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also see this new guide: Tuning Performance for Deployment

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess for now let's just keep our value, and if we get a reply we can still adjust the value later on.

Comment on lines +32 to +34
# Specify the PID file. Defaults to tmp/pids/server.pid in development.
# In other environments, only set the PID file if requested.
pidfile ENV["PIDFILE"] if ENV["PIDFILE"]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With regards to the pidfile and your note, see also this issue.

I don't think we need such a file in production at all. In docker/production/entrypoint_worker.sh and docker/entrypoint-dev-test.sh, we manually remove the file.

While with Rails 7.2, this file should no longer be generated (since we don't request it; we never set the PIDFILE env variable), let's leave the rm -f tmp/pids/server.pid statement in the entrypoint to be sure. Anyways, in the dev/test setup we cannot remove that line since in the dev environment, a PID file will always be generated, see this comment.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this should be fine, feel free to resolve.

@Splines Splines requested a deployment to testing-review May 2, 2025 16:46 — with GitHub Actions Waiting
@Splines Splines changed the title Upgrade Ruby to 3.3.7 and Rails to 7.2.2.1 Upgrade Ruby to 3.3.8 and Rails to 7.2.2.1 May 2, 2025
@Splines Splines requested a deployment to testing-review May 2, 2025 17:54 — with GitHub Actions Waiting
# config.assume_ssl = true

# Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
# config.force_ssl = true
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From the documentation:

Forces all requests to be served over HTTPS, and sets "https://" as the default protocol when generating URLs.

This kind of redirect already happens in apache via this config:

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{HTTPS} off
    RewriteRule (.*) https://%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
</IfModule>

so why not also use it directly in Rails such that all generated URLs automatically have https:// as default protocol.

Copy link
Member

@Splines Splines May 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Config option activated via commit 19d726b. Feel free to resolve.

Copy link
Member

@Splines Splines left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you already look into Brakeman?

Brakeman is a great way to prevent common security vulnerabilities in Rails from going into production.

And jemalloc? See also this blog post.

Maybe something like Brakeman is something for another PR, but I feel like a small like adding jemalloc could still be incorporated here.

As those are external dependencies, I propose to introduce them in future PRs, should we want to include them.

Splines added 2 commits May 2, 2025 21:17
Debian Bookworm (12) only ships postgresql-client-15 and no longer v13 [1].
Therefore, we update postgresl for the local setup. We can then update
the postgresql version on the server at a later stage and first try to
make sure that locally everything works fine.

[1] https://packages.debian.org/bookworm/postgresql-client
@Splines Splines requested a deployment to testing-review May 2, 2025 19:19 — with GitHub Actions Waiting
@Splines Splines requested a deployment to testing-review May 2, 2025 19:43 — with GitHub Actions Waiting
@@ -1 +1 @@
Rails.application.config.active_job.queue_adapter = :sidekiq
Rails.application.config.active_job.queue_adapter = :sidekiq unless Rails.env.test?
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix you guessed was exactly what we needed to fix the failing unit tests ✨

Splines added 3 commits May 2, 2025 23:55
See release 4.1.2 of spring where they drop dependency on mutex_m.
Therefore, our problem is elegantly solved without the need for a
new dependency.

https://github.com/rails/spring/blob/main/CHANGELOG.md#412
@Splines Splines requested a deployment to testing-review May 2, 2025 22:05 — with GitHub Actions Waiting
@Splines Splines changed the title Upgrade Ruby to 3.3.8 and Rails to 7.2.2.1 Upgrade Ruby (3.1.4 -> 3.3.8) & Rails (7.1.3 -> 7.2.2.1) May 2, 2025
@@ -20,7 +20,7 @@ class Voucher < ApplicationRecord
DEFAULT_EXPIRATION_DAYS = 3

ROLE_HASH = { tutor: 0, editor: 1, teacher: 2, speaker: 3 }.freeze
enum role: ROLE_HASH
enum :role, ROLE_HASH
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This violation should have been detected by RuboCop. Opened an issue for it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really weird. I've created a new issue for it #768. For now, let's ignore this in this Rails upgrade that doesn't have to do with it and fix the RuboCop issue afterwards. Feel free to resolve this thread.

@Splines Splines requested a deployment to testing-review May 3, 2025 09:56 — with GitHub Actions Waiting
@@ -17,7 +17,7 @@
# Ensures that a master key has been made available in ENV["RAILS_MASTER_KEY"],
# config/master.key, or an environment key such as config/credentials/production.key.
# This key is used to decrypt credentials (and other encrypted files).
config.require_master_key = true
# config.require_master_key = true
Copy link
Member

@Splines Splines May 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you make this a comment? See also the config option.

@@ -2,7 +2,6 @@ class Interaction < InteractionsRecord
scope :created_between, lambda { |start_date, end_date|
where(created_at: start_date.beginning_of_day..end_date.end_of_day)
}
require "csv"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure why you removed this line (also in other files)? This is not a RuboCop violation. Without this line, this class will throw an error if CSV is not magically loaded before loading this class and we don't want to risk that, right?

On another point: it'd be better to place this at the top of the file to be better visible since that's the usual place where we put the require statements.

Copy link
Member

@Splines Splines May 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"if CSV is not magically loaded before loading this class"

Turns out that's exactly what is done. But there's no magic: instead it is just the line Bundler.require(*Rails.groups) in config/application.rb which is responsible for this behavior. So indeed, removing these require lines as you did works just fine.

As CSV functionality is not used in many places, we might discuss if we instead want to do a gem "csv", "~> 3.3", require: false instead. Then, only require it at the respective places (at the very top of files that use the CSV class). Of course, one single gem doesn't cut startup times, but in total with many gems it might make a difference.

Copy link
Member

@Splines Splines left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've reviewed all changes now.

@@ -1,3 +1,5 @@
require "active_support/core_ext/integer/time"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You added this require here. Based on this answer, I suspect it coming from new Rails templates themselves. However, you only included this here, while also development.rb and docker_development.rb contain a time-related statement: 2.days.to_i.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
dependencies Pull requests that update a dependency file
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants