DEV Community

Jairo Andrés Orjuela
Jairo Andrés Orjuela

Posted on

Upgrade from Rails 6.1.7 to Rails 7.0

Rails Upgrade

Upgrade from Rails 6.1.7 to Rails 7.0 in an API type application.

Before the upgrade the specs are:

  • I have a Mac M1 MacOs ventura
  • Rails 6.1.7
  • Ruby 2.7.3
  • PostgreSQL 13.0 client for the mac
  • Redis server 6.2.4

Step by step upgrade:

  • There is a recommendation regarding not upgrading from a very old version to a very recent one, for example, it is not recommended to upgrade from Rails 5 to Rails 7, in this case it does not apply, as we are moving from 6.1 to 7 which is fine.
  • Copy and paste our Gemfile.lock into RailsBumb so we can check which of our gems are going to generate errors or problems.
  • Use the gem "next_rails" to check which gems we need to update, when we have it installed we will just do a bundle_report compatibility --rails-version=desired_version, after this we can update the gems that appear in the report.
  • Updating gems:
    • If the report asks us to update gems that are part of Rails such as ActionMailer or ActionText these will be updated with the version change to Rails 7. If the gems are installed by us, obviously we must do the update.
    • It is not advisable to have a fixed version of a gem in our Gemfile so it is a good time to remove that.
  • After updating the gems we can now in our Gemfile update the Rails version and run bundle update.
  • When the update is done the first thing to do is to change the load_defaults to Rails 7 in our config/application.rb file.
  • In my case I use Spring this gem is on its 2.1.1 version for some reason next-rails didn't take it into account, but it should be updated to a 3X version.
    • When I tried to update the gem it told me that I could not because it was locked, for this what I did was to delete my Gemfile.lock.
    • Then in config/environments/test.rb I left it set to false.
  • Configure Zeitwerk.
    • Zeitwerk is the only way in Rails 7 to safely load files and avoid overuse of require.
    • As you have already made the switch to Rails 7 in the application in config/application.rb you should remove the config.autoloader line.
    • Check if everything is already running fine with bin/rails runner 'p Rails.autoloaders.zeitwerk_enabled?' should return true or the respective warnings.
  • Encryption
    • At this point, when starting the server I was getting an ActiveSupport::MessageEncryptor::InvalidMessage error because of the encryption.
    • In the API the attributes are encrypted following this tutorial, but when updating Rails the encryption changes, because Rails 7 uses SHA256 while in the previous versions SHA1 is used, but this protocol is obsolete, to solve this you must specify to continue encrypting with SHA1 while then the change is made to use the encrypted attributes of Rails 7, to solve this it worked for me to add the hash_digest_class like this:
class EncryptionService
  KEY = ActiveSupport::KeyGenerator.new(
    Rails.application.credentials[:secret_key_base],
    hash_digest_class: OpenSSL::Digest::SHA1
  ).generate_key(
    Rails.application.credentials[:ENCRYPTION_SERVICE_SALT],
    ActiveSupport::MessageEncryptor.key_len
  ).freeze
Enter fullscreen mode Exit fullscreen mode
  • When running the tests I found the error RuntimeError: Foreign key violations found in your fixture data, this is because in previous versions you could have fixtures with a missing association, this will no longer be possible in Rails 7.
    • One option is in application.rb add the line config.active_record.verify_foreign_keys_for_fixtures = false.
    • The other option is to fix the errors in the fixtures (which is recommended), to detect which tables we have wrong, first we reset and load the test database and then enter in the console like this:
RAILS_ENV=test bin/rails db:reset
RAILS_ENV=test bin/rails db:fixtures:load
RAILS_ENV=test bin/rails c 
Enter fullscreen mode Exit fullscreen mode
  • Then we run this query to identify if there are tables that are missing an association so we can correct the fixtures and the error will be fixed:
ActiveRecord::Base.connection.execute(<<~SQL)
  do $$$
    declare r record;
  BEGIN
  FOR r IN (
    SELECT FORMAT(
      'UPDATE pg_constraint SET convalidated=false WHERE conname = ''%I''; ALTER TABLE %I VALIDATE CONSTRAINT %I;',
      constraint_name,
      table_name,
      constraint_name
    ) AS constraint_check
    FROM information_schema.table_constraints WHERE constraint_type = 'FOREIGN KEY'
  )
    LOOP
      EXECUTE (r.constraint_check);
    END LOOP;
  END;
  $$;
SQL
Enter fullscreen mode Exit fullscreen mode
  • The following error to be corrected was ActionDispatch::Request::Session::DisabledSessionError: Your application has sessions disabled. To write to the session you must first configure a session store
    • In config/application.rb, I had the line config.middleware.use ActionDispatch::Cookies to solve this solution from this thread of Github worked for me.

Github thread

This was the whole process in my case. The support guides and documentation for this update were:

Top comments (0)