My journey trying to upgrade to Rails 7.1

Several weeks ago I decided to upgrade a rails 7.0.8 app to 7.1.1. It has been hell and I’m about reset my git repo back to my last 7.0 commit and wait for the dust to clear! I am not expert in rails but I’ve been using it since pre 1.0 release. I have 3 apps that are more or less private running on Digital Oceans VPN and staged on a local Debian server. Most are in SteveCode, I don’t have tests - could never get my arms around it - I just push the car back up the hill and see it the brakes fail again!

I initially created a 7.1 branch on one of the apps and did the update in that branch. I had numerous problems and asked for help a few times (after gem updates deploy fails with can’t find service #369, rails 7.1 active_record column serialization documentation #49978. Most of my original problems came from Capistrano and ‘capistrano/puma’ updates that changed versions in the last few weeks. That took a little while to get straight and got the app to run with bin/dev.

But I was in a branch and you can’t deploy a branch. I had made a few changes to the 7.0 head and ended up deleting the 7.1 branch, adding a new one, did the update all over and got it running locally. I then merged that branch to master and tried to deploy to staging.

A whole group of new problems.

Can’t setup rails: psych/yaml issue. This error was it couldn’t find a yaml.h file. I followed their advise and installed libyaml locally and on the staging server.

That got me to the next/current problem, Puma running in a loop on the staging server with the main error:

bundler: failed to load command: puma (/home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/bin/puma)
/home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/zeitwerk-2.6.12/lib/zeitwerk/loader/helpers.rb:135:in `const_g
et': uninitialized constant CoreExtensions::Array::TestArray (NameError)
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/zeitwerk-2.6.12/lib/zeitwerk/loader/helpers.rb:13
5:in `cget'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/zeitwerk-2.6.12/lib/zeitwerk/loader/eager_load.rb
:175:in `block in actual_eager_load_dir'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/zeitwerk-2.6.12/lib/zeitwerk/loader/helpers.rb:40
:in `block in ls'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/zeitwerk-2.6.12/lib/zeitwerk/loader/helpers.rb:25
:in `each'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/zeitwerk-2.6.12/lib/zeitwerk/loader/helpers.rb:25
:in `ls'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/zeitwerk-2.6.12/lib/zeitwerk/loader/eager_load.rb
:170:in `actual_eager_load_dir'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/zeitwerk-2.6.12/lib/zeitwerk/loader/eager_load.rb
:17:in `block (2 levels) in eager_load'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/zeitwerk-2.6.12/lib/zeitwerk/loader/eager_load.rb
:16:in `each'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/zeitwerk-2.6.12/lib/zeitwerk/loader/eager_load.rb
:16:in `block in eager_load'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/zeitwerk-2.6.12/lib/zeitwerk/loader/eager_load.rb
:10:in `synchronize'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/zeitwerk-2.6.12/lib/zeitwerk/loader/eager_load.rb
:10:in `eager_load'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/zeitwerk-2.6.12/lib/zeitwerk/loader.rb:379:in `bl
ock in eager_load_all'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/zeitwerk-2.6.12/lib/zeitwerk/loader.rb:377:in `ea
ch'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/zeitwerk-2.6.12/lib/zeitwerk/loader.rb:377:in `ea
ger_load_all'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/railties-7.1.1/lib/rails/application/finisher.rb:
80:in `block in <module:Finisher>'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/railties-7.1.1/lib/rails/initializable.rb:32:in `
instance_exec'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/railties-7.1.1/lib/rails/initializable.rb:32:in `
run'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/railties-7.1.1/lib/rails/initializable.rb:61:in `
block in run_initializers'
  from /home/developer/.rbenv/versions/3.0.1/lib/ruby/3.0.0/tsort.rb:228:in `block in tsort_each'
  from /home/developer/.rbenv/versions/3.0.1/lib/ruby/3.0.0/tsort.rb:350:in `block (2 levels) in each_strongly_con
nected_component'
  from /home/developer/.rbenv/versions/3.0.1/lib/ruby/3.0.0/tsort.rb:431:in `each_strongly_connected_component_fro
m'
  from /home/developer/.rbenv/versions/3.0.1/lib/ruby/3.0.0/tsort.rb:349:in `block in each_strongly_connected_comp
onent'
  from /home/developer/.rbenv/versions/3.0.1/lib/ruby/3.0.0/tsort.rb:347:in `each'
  from /home/developer/.rbenv/versions/3.0.1/lib/ruby/3.0.0/tsort.rb:347:in `call'
  from /home/developer/.rbenv/versions/3.0.1/lib/ruby/3.0.0/tsort.rb:347:in `each_strongly_connected_component'
  from /home/developer/.rbenv/versions/3.0.1/lib/ruby/3.0.0/tsort.rb:226:in `tsort_each'
  from /home/developer/.rbenv/versions/3.0.1/lib/ruby/3.0.0/tsort.rb:205:in `tsort_each'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/railties-7.1.1/lib/rails/initializable.rb:60:in `
run_initializers'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/railties-7.1.1/lib/rails/application.rb:423:in `i
nitialize!'
  from /home/developer/apps/ptgolf/current/config/environment.rb:5:in `<top (required)>'
  from /home/developer/apps/ptgolf/current/config.ru:3:in `require_relative'
  from /home/developer/apps/ptgolf/current/config.ru:3:in `block in <main>'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/rack-3.0.8/lib/rack/builder.rb:103:in `eval'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/rack-3.0.8/lib/rack/builder.rb:103:in `new_from_s
tring'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/rack-3.0.8/lib/rack/builder.rb:94:in `load_file'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/rack-3.0.8/lib/rack/builder.rb:64:in `parse_file'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/puma-6.4.0/lib/puma/configuration.rb:368:in `load
_rackup'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/puma-6.4.0/lib/puma/configuration.rb:290:in `app'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/puma-6.4.0/lib/puma/runner.rb:162:in `load_and_bi
nd'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/puma-6.4.0/lib/puma/single.rb:44:in `run'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/puma-6.4.0/lib/puma/launcher.rb:194:in `run'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/puma-6.4.0/lib/puma/cli.rb:75:in `run'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/gems/puma-6.4.0/bin/puma:10:in `<top (required)>'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/bin/puma:23:in `load'
  from /home/developer/apps/ptgolf/shared/bundle/ruby/3.0.0/bin/puma:23:in `<top (required)>'
  from /home/developer/.rbenv/versions/3.0.1/lib/ruby/3.0.0/bundler/cli/exec.rb:63:in `load'
  from /home/developer/.rbenv/versions/3.0.1/lib/ruby/3.0.0/bundler/cli/exec.rb:63:in `kernel_load'
  from /home/developer/.rbenv/versions/3.0.1/lib/ruby/3.0.0/bundler/cli/exec.rb:28:in `run'
  from /home/developer/.rbenv/versions/3.0.1/lib/ruby/3.0.0/bundler/cli.rb:494:in `exec'
  from /home/developer/.rbenv/versions/3.0.1/lib/ruby/3.0.0/bundler/vendor/thor/lib/thor/command.rb:27:in `run'
  from /home/developer/.rbenv/versions/3.0.1/lib/ruby/3.0.0/bundler/vendor/thor/lib/thor/invocation.rb:127:in `inv
oke_command'
  from /home/developer/.rbenv/versions/3.0.1/lib/ruby/3.0.0/bundler/vendor/thor/lib/thor.rb:392:in `dispatch'
  from /home/developer/.rbenv/versions/3.0.1/lib/ruby/3.0.0/bundler/cli.rb:30:in `dispatch'
  from /home/developer/.rbenv/versions/3.0.1/lib/ruby/3.0.0/bundler/vendor/thor/lib/thor/base.rb:485:in `start'
  from /home/developer/.rbenv/versions/3.0.1/lib/ruby/3.0.0/bundler/cli.rb:24:in `start'
  from /home/developer/.rbenv/versions/3.0.1/lib/ruby/gems/3.0.0/gems/bundler-2.2.15/libexec/bundle:49:in `block i
n <top (required)>'
  from /home/developer/.rbenv/versions/3.0.1/lib/ruby/3.0.0/bundler/friendly_errors.rb:130:in `with_friendly_error
s'
  from /home/developer/.rbenv/versions/3.0.1/lib/ruby/gems/3.0.0/gems/bundler-2.2.15/libexec/bundle:37:in `<top (r
equired)>'
  from /home/developer/.rbenv/versions/3.0.1/bin/bundle:23:in `load'
  from /home/developer/.rbenv/versions/3.0.1/bin/bundle:23:in `<main>'

I think there may of been a few more errors, but forget what they were. I had problems with serialized columns, but finally got those defined correctly with :coder and :type. It’s apparent I don’t know what I’m doing and, as I said earlier, about reset my git repo back to my last 7.0 commit and wait for the dust to clear!

I think Psych stuff was in 7.0, but not as a gem. I’m lost and just a hobbyist - been retired for 13 years and at 79, getting too old for this stuff.

The CoreExtensions::Array::TestArray error may’ve come from inside your app, because this TestArray const doesn’t seem to show up anywhere in Rails code (and generally on the web). Try to search your codebase for TestArray, see where it might be referenced. Could be a thread to start pulling.

I had tried that earlier and there was nothing found. I had been thinking about one of my serialized columns that was an Array. When they/rails added coder: required on serialized columns (maybe 7.0.8), I searched for how to add that and could not find any guide that referenced the attributes for serialize. Maybe from the error message I picked up that it was coder:. I have one serialized column that was defined:

  serialize :role, Array
# which was changed to
  serialize :role, coder: YAML, Array
# that broke in 7.1 and I added type:
    serialize :role, coder: YAML, type: Array

Again I could not find the attributes for serialize. Don/t know where I got type: from but I changed type: to class: and it still worked. Would still like to find a reference!

The TestArray still puzzled me. It had to do with array and the word test. I search for all occurrences of ‘Array’ and found

~/Work/current/ptgolf7/lib/core_extensions/array/test_array.rb:
    1  # just a proof of concept
    2  module CoreExtensions
    3:   module Array
    4      def test_array
    5        puts "test_array"

BOOM!

I had experimented with adding core_extension to my lib directory and added a monkey_patch to initializers. I was trying to get one of the serialized columns into a Struct. I found a better way but the core_extentions folder was still in lib.

I removed the junk code and money patch and it deployed to staging without any errors, Now if I can figure out how to get Safari to access my staging server, that running http and not https, I’ll be happy. It works in Firebox but wants to redirect to https in Safari.

Also I had to add back config.active_record.yaml_column_permitted_classes = [Symbol, Hash, Array, ActiveSupport::HashWithIndifferentAccess] back to my application.rb file. I’ve regretted using using HashWithIndifferentAccess in one of the columns and it’s on my bucket list to change. I just may change all of them to JSON with a conversion.

Thank you for letting me think a little harder on where TestArray was coming from.

Glad you were able to find that code!

The serialize documentation is here. I usually have better luck when I search for something like “activerecord serialize” instead of “rails serialize”.

I looked around, and I believe Safari is listening to what your Rails app telegraphs, and then remembers it in its own cache. Your rails app probably has config.force_ssl = true in the production.rb file, which is also what you probably run on staging. You could, for example, make it work via ENV var instead, like this:

config.force_ssl = %w[f false no 0].exclude?(ENV['FORCE_SSL'])

And launch the staging app with FORCE_SSL=no (by default it will be true, so production app will remain unchanged).

And according to this post I found, you should go to Safari → Settings → Privacy → Manage Website Data…, in there find the domain of your website, and remove it. This should make Safari “forget” that your site ever wanted to redirect to https.

I remember going to active record serialize, but a while back. Just looking in the wrong place. I now know where I saw type:

Did find the Safari settings to reset and added config.force_ssl . It was commented out.

Thanks again. Time to clean up some stuff before I deploy to production.

Well, if it was commented out, then adding it and having to set variable is unnecessary. Probably just need to clear that safari domain thing.