Ruby 3.0.4 -> 3.2.2、Rails 6.1.0 -> 7.1.4の作業ログ

# 基本手順
大変勉強になりました。ぜひご一読ください。

https://qiita.com/jnchito/items/0ee47108972a0e302caf

## Gemfile更新
```diff
source 'https://rubygems.org'
git_source(:github) { |repo| "https://github.com/#{repo}.git" }

- ruby '3.0.4'
+ ruby '3.2.2'

# Bundle edge Rails instead: gem 'rails', github: 'rails/rails'
- gem 'rails', '~> 6.1.0'
+ gem 'rails', '~> 7.1.4'
```

## Dockerfile更新
```diff
- FROM ruby:3.0.4
+ FROM ruby:3.2.2

# environment
ENV APP_ROOT /app
```

# トラブルシューティング
## bundle installでversion conflict発生
bundle installすると以下のエラーが出ました。記載の通り、Gemfile.lockでは6.1.6となっているが、Gemfileは7.1.4を求めているためです。末尾に書いてある通り、bundle updateをします。
```console
Bundler could not find compatible versions for gem "activesupport":
  In snapshot (Gemfile.lock):
    activesupport (= 6.1.6)

  In Gemfile:
    rails (~> 7.1.4) was resolved to 7.1.4, which depends on
      activesupport (= 7.1.4)

    webpacker (~> 5.0) was resolved to 5.4.3, which depends on
      railties (>= 5.2) was resolved to 6.1.6, which depends on
        activesupport (= 6.1.6)

Running `bundle update` will rebuild your snapshot from scratch, using only
the gems in your Gemfile, which may resolve the conflict.
```

## bundle updateが終わらない
1時間待ってもこの状況。ドットが増えるだけ。Gemfile.lockを削除して、bundle installしました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192137/55894eb1-fd57-6e01-a1df-1bf424c703b4.png)

### 追記
以下の順番でコマンドを実行するとすんなりいく時がありました。
```bash
bundle update rails
bundle update 
```

## nokogiriでconflict発生
以下のエラーが発生。nokogiri v1.12.5をインストールしようとするが、Rails v7.1.4に対応していないとのこと
```console
root@31976fb95aec:/app# bundle install
Fetching gem metadata from https://rubygems.org/........
Resolving dependencies...
Could not find compatible versions

Because rails >= 7.1.4, < 7.2.0.beta1 depends on actionview = 7.1.4
  and actionview >= 7.1.0.beta1 depends on rails-html-sanitizer ~> 1.6,
  rails >= 7.1.4, < 7.2.0.beta1 requires rails-html-sanitizer ~> 1.6.
And because rails-html-sanitizer >= 1.6.0.rc1 depends on nokogiri ~> 1.14,
  rails >= 7.1.4, < 7.2.0.beta1 requires nokogiri ~> 1.14.
So, because Gemfile depends on rails ~> 7.1.4
  and Gemfile depends on nokogiri = 1.12.5,
  version solving has failed.
```

Gemfileを見ると、バージョンを指定していたのでバージョン指定を削除して、再度bundle install
```diff
- gem 'nokogiri', '1.12.5'
+ gem 'nokogiri'
```

## debaseのインストールでエラー
以下のエラーが発生。よくわからないし、ステップ実行でデバッグすることもあまりないので、debaseを削除しました。
```console
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    current directory: /usr/local/bundle/gems/debase-0.2.4.1/ext
/usr/local/bin/ruby extconf.rb
checking for vm_core.h... no
checking for vm_core.h... no
**************************************************************************
No source for ruby-3.2.2-p53 (revision e51014f9c05aa65cbf203442d37fef7c12390015) provided with
debase-ruby_core_source gem. Falling back to ruby-3.2.0-p0.
**************************************************************************
checking for vm_core.h... yes
checking for iseq.h... yes
checking for version.h... yes
checking for vm_core.h... yes
checking for vm_insnhelper.h... no
Makefile creation failed
*************************************************************

  NOTE: If your headers were not found, try passing
        --with-ruby-include=PATH_TO_HEADERS      

*************************************************************

*** extconf.rb failed ***
Could not create Makefile due to some reason, probably lack of necessary
libraries and/or headers.  Check the mkmf.log file for more details.  You may
need configuration options.

Provided configuration options:
        --with-opt-dir
        --without-opt-dir
        --with-opt-include
        --without-opt-include=${opt-dir}/include
        --with-opt-lib
        --without-opt-lib=${opt-dir}/lib
        --with-make-prog
        --without-make-prog
        --srcdir=.
        --curdir
        --ruby=/usr/local/bin/$(RUBY_BASE_NAME)
        --with-ruby-dir
        --without-ruby-dir
        --with-ruby-include
        --without-ruby-include=${ruby-dir}/include
        --with-ruby-lib
        --without-ruby-lib=${ruby-dir}/lib
        --with-vm_core-dir
        --without-vm_core-dir
        --with-vm_core-include
        --without-vm_core-include=${vm_core-dir}/include
        --with-vm_core-lib
        --without-vm_core-lib=${vm_core-dir}/lib
        --with-iseq-dir
        --without-iseq-dir
        --with-iseq-include
        --without-iseq-include=${iseq-dir}/include
        --with-iseq-lib
        --without-iseq-lib=${iseq-dir}/lib
        --with-version-dir
        --without-version-dir
        --with-version-include
        --without-version-include=${version-dir}/include
        --with-version-lib
        --without-version-lib=${version-dir}/lib
        --with-vm_insnhelper-dir
        --without-vm_insnhelper-dir
        --with-vm_insnhelper-include
        --without-vm_insnhelper-include=${vm_insnhelper-dir}/include
        --with-vm_insnhelper-lib
        --without-vm_insnhelper-lib=${vm_insnhelper-dir}/lib

To see why this extension failed to compile, please check the mkmf.log which can be found here:

  /usr/local/bundle/extensions/x86_64-linux/3.2.0/debase-0.2.4.1/mkmf.log

extconf failed, exit code 1

Gem files will remain installed in /usr/local/bundle/gems/debase-0.2.4.1 for inspection.
Results logged to /usr/local/bundle/extensions/x86_64-linux/3.2.0/debase-0.2.4.1/gem_make.out

  /usr/local/lib/ruby/3.2.0/rubygems/ext/builder.rb:119:in `run'
  /usr/local/lib/ruby/3.2.0/rubygems/ext/ext_conf_builder.rb:27:in `build'
  /usr/local/lib/ruby/3.2.0/rubygems/ext/builder.rb:187:in `build_extension'
  /usr/local/lib/ruby/3.2.0/rubygems/ext/builder.rb:221:in `block in build_extensions'
  /usr/local/lib/ruby/3.2.0/rubygems/ext/builder.rb:218:in `each'
  /usr/local/lib/ruby/3.2.0/rubygems/ext/builder.rb:218:in `build_extensions'
  /usr/local/lib/ruby/3.2.0/rubygems/installer.rb:843:in `build_extensions'
  /usr/local/lib/ruby/3.2.0/bundler/rubygems_gem_installer.rb:72:in `build_extensions'
  /usr/local/lib/ruby/3.2.0/bundler/rubygems_gem_installer.rb:28:in `install'
  /usr/local/lib/ruby/3.2.0/bundler/source/rubygems.rb:200:in `install'
  /usr/local/lib/ruby/3.2.0/bundler/installer/gem_installer.rb:54:in `install'
  /usr/local/lib/ruby/3.2.0/bundler/installer/gem_installer.rb:16:in `install_from_spec'
  /usr/local/lib/ruby/3.2.0/bundler/installer/parallel_installer.rb:156:in `do_install'
  /usr/local/lib/ruby/3.2.0/bundler/installer/parallel_installer.rb:147:in `block in worker_pool'
  /usr/local/lib/ruby/3.2.0/bundler/worker.rb:62:in `apply_func'
  /usr/local/lib/ruby/3.2.0/bundler/worker.rb:57:in `block in process_queue'
  /usr/local/lib/ruby/3.2.0/bundler/worker.rb:54:in `loop'
  /usr/local/lib/ruby/3.2.0/bundler/worker.rb:54:in `process_queue'
  /usr/local/lib/ruby/3.2.0/bundler/worker.rb:90:in `block (2 levels) in create_threads'

An error occurred while installing debase (0.2.4.1), and Bundler cannot continue.

In Gemfile:
  debase
```

Gemfileから削除しました。
```diff
-  gem 'debase'
-  gem 'ruby-debug-ide' 
```

## RSpecを実行するとDatabaseCleanerでエラーがでる
"3/"をIntergerに直せないというエラーのようです。

```console
root@2270bf2d2ad8:/app# bundle exec rspec
DEPRECATION WARNING: Support for `config.active_support.cache_format_version = 6.1` has been deprecated and will be removed in Rails 7.2.

Check the Rails upgrade guide at https://guides.rubyonrails.org/upgrading_ruby_on_rails.html#new-activesupport-cache-serialization-format
for more information on how to upgrade.
 (called from <top (required)> at /app/config/environment.rb:5)

An error occurred in a `before(:suite)` hook.
Failure/Error: DatabaseCleaner[:redis].clean_with(:deletion)

ArgumentError:
  invalid value for Integer(): "3/"
# /usr/local/bundle/gems/redis-client-0.22.2/lib/redis_client/url_config.rb:33:in `Integer'
# /usr/local/bundle/gems/redis-client-0.22.2/lib/redis_client/url_config.rb:33:in `db'
# /usr/local/bundle/gems/redis-client-0.22.2/lib/redis_client/config.rb:198:in `initialize'
# /usr/local/bundle/gems/redis-client-0.22.2/lib/redis_client.rb:166:in `new'
# /usr/local/bundle/gems/redis-client-0.22.2/lib/redis_client.rb:166:in `config'
# /usr/local/bundle/gems/redis-5.3.0/lib/redis/client.rb:23:in `config'
# /usr/local/bundle/gems/redis-5.3.0/lib/redis.rb:142:in `initialize_client'
# /usr/local/bundle/gems/redis-5.3.0/lib/redis.rb:73:in `initialize'
# /usr/local/bundle/gems/database_cleaner-redis-2.0.0/lib/database_cleaner/redis/deletion.rb:43:in `new'
# /usr/local/bundle/gems/database_cleaner-redis-2.0.0/lib/database_cleaner/redis/deletion.rb:43:in `connection'
# /usr/local/bundle/gems/database_cleaner-redis-2.0.0/lib/database_cleaner/redis/deletion.rb:13:in `clean'
# /usr/local/bundle/gems/database_cleaner-core-2.0.1/lib/database_cleaner/cleaner.rb:65:in `clean_with'
# ./spec/rails_helper.rb:108:in `block (2 levels) in <top (required)>'


Deprecation Warnings:

Rails 7.1 has deprecated the singular fixture_path in favour of an array.You should migrate to plural:


If you need more of the backtrace for any of these deprecations to
identify where to make the necessary changes, you can configure
`config.raise_errors_for_deprecations!`, and it will turn the
deprecation warnings into errors, giving you the full backtrace.

1 deprecation warning total

Finished in 3.48 seconds (files took 8.72 seconds to load)
0 examples, 0 failures, 1 error occurred outside of examples
```

`config/enviroment/test.rb` を見ると、以下のように設定されており、
```ruby
config.cache_store = :redis_cache_store, { url: ENV['REDIS_CACHE_URL'] }
```
REDIS_CACHE_URLには以下が設定されていました。
```
`redis://xxxxxxxxxxxxxxxxxxxx_redis:6379/3/`
```
この末尾のスラッシュを外して再度`bundle exec rspec` をしました。

## Auditedが失敗する
以下のようなエラーが出ます。

```:config/application.rb
     Psych::DisallowedClass:
       Tried to load unspecified class: ActiveSupport::TimeWithZone
     # /usr/local/bundle/gems/audited-5.7.0/lib/audited/audit.rb:22:in `load'
     # /usr/local/bundle/gems/audited-5.7.0/lib/audited/auditor.rb:366:in `block in write_audit'
     # /usr/local/bundle/gems/audited-5.7.0/lib/audited/auditor.rb:365:in `write_audit'
     # /usr/local/bundle/gems/audited-5.7.0/lib/audited/auditor.rb:334:in `audit_create'
     # /usr/local/bundle/gems/bullet-7.2.0/lib/bullet/active_record61.rb:6:in `_create_record'
     # /usr/local/bundle/gems/factory_bot-6.4.6/lib/factory_bot/evaluation.rb:15:in `create'
     # /usr/local/bundle/gems/factory_bot-6.4.6/lib/factory_bot/strategy/create.rb:12:in `block in result'
     # /usr/local/bundle/gems/factory_bot-6.4.6/lib/factory_bot/strategy/create.rb:9:in `result'
     # /usr/local/bundle/gems/factory_bot-6.4.6/lib/factory_bot/factory.rb:43:in `run'
     # /usr/local/bundle/gems/factory_bot-6.4.6/lib/factory_bot/factory_runner.rb:29:in `block in run'
     # /usr/local/bundle/gems/factory_bot-6.4.6/lib/factory_bot/factory_runner.rb:28:in `run'
     # /usr/local/bundle/gems/factory_bot-6.4.6/lib/factory_bot/strategy_syntax_method_registrar.rb:28:in `block in define_singular_strategy_method'
```

auditedのIssueが上がっており、現在対応中の模様。Issue内のコメントにある通り、`config/application.rb` にyaml_column_permitted_classesを追記する。

https://github.com/collectiveidea/audited/issues/631#issuecomment-1213641862

```ruby
config.active_record.yaml_column_permitted_classes =
  %w[String Integer NilClass Float Time Date FalseClass Hash Array DateTime TrueClass BigDecimal
      ActiveSupport::TimeWithZone ActiveSupport::TimeZone ActiveSupport::HashWithIndifferentAccess]
```

## Ransackにransackable_attributesが必要
以下のようなエラーが出ます。

```
     RuntimeError:
       Ransack needs XXXXXXXXXX attributes explicitly allowlisted as
       searchable. Define a `ransackable_attributes` class method in your `XXXXXXXXXX`
       model, watching out for items you DON'T want searchable (for
       example, `XXXXXXXXXX`, `XXXXXXXXXX`, `XXXXXXXXXX` or
       other sensitive information). You can use the following as a base:
```

調べればたくさん対策案が出てきます。今回は以下のコードを挿入して対応しました。
```ruby
# app/models/application_record.rb
class ApplicationRecord < ActiveRecord::Base
  # ...

  def self.ransackable_associations(auth_object = nil)
    @ransackable_associations ||= reflect_on_all_associations.map { |a| a.name.to_s }
  end

  def self.ransackable_attributes(auth_object = nil)
    @ransackable_attributes ||= column_names + _ransackers.keys + _ransack_aliases.keys + attribute_aliases.keys
  end
end
```

## devise_token_authでundefined method `downcase' が発生
RSpec実行中に以下のエラーが発生
```
NoMethodError - undefined method `downcase' for nil:NilClass:

Started GET "/api/v1/xxxxxxxxxxxxx?yyyy=1" for 127.0.0.1 at 2024-09-10 09:58:44 +0900
Processing by Api::V1::XXXXXXXXXXXXXXXXXXX#index as JSON
  Parameters: {"yyyy"=>"1"}
[active_model_serializers] Rendered ActiveModel::Serializer::Null with Hash (0.08ms)
Filter chain halted as :authenticate_admin! rendered or redirected
Completed 401 Unauthorized in 202ms (Views: 3.9ms | ActiveRecord: 0.0ms | Allocations: 335323)
```

めっちゃ分かりにくいですが、authenticate_admin!をやろうとしていますが、undefined method `downcase' for nil:NilClass:が発生し、401が返っています。cancancanかdevise_token_authの認証認可で失敗しています。

調べるとこちらの記事がヒット

https://qiita.com/ginger-yell/items/d69469f51c28bb05b03a

記載の通り、config/initializers/devise_token_auth.rbに1行追加すると解決できました。

```config/initializers/devise_token_auth.rb
# Makes it possible to change the headers names
  config.headers_names = {:'access-token' => 'access-token',
                         :'client' => 'client',
                         :'expiry' => 'expiry',
                         :'uid' => 'uid',
                         :'token-type' => 'token-type',
                         # ↓ここを追加！！！
                         :'authorization' => 'authorization'}
```

## unfが無い
以下のエラーが発生
```
      Failure/Error: require "unf"
      
      LoadError:
        cannot load such file -- unf
```

Gemfile.lockの変更履歴を見ると`http -> http-cookie -> domain_name -> unf` の依存関係でたまたま入っていただけだった。domain_nameがバージョンアップに伴いunfを要求しなくなったのでエラーが発生していた

Gemfileに追加して解決
```diff
+ gem 'unf'
```

## DateTime.new(0) の戻り値が変わってる
どこかのタイミングで変わったっぽいです。DBのindexを効かせるために、Datetime型の列に対してmigrationでDateTime.new(0)をデフォルト値として使っている個所があり、軒並みRspecが失敗しました。

```
以前：Sat, 01 Jan 0000 09:18:59.000000000 LMT +09:18
最新：Thu, 01 Jan 0000 00:00:00 +0000
```

Rspecの検査値を固定値に変更して対応しました
```ruby
- expect(value.datetime_zero).to eq(DateTime.new(0))
+ expect(value.datetime_zero.to_s).to eq(DateTime.new(0, 1, 3, 9, 18, 59, "+09:18").to_s)
```

## fixture_file_uploadのパスが変わった
fixture_file_uploadが`/app/spec/fixtures/`から`/app/spec/fixtures/fixtures/`になったっぽい。と思ったら、rubocopでRails/FilePathが指摘されるようになり自動修正した結果、発生したエラーでした。
```:エラー
Failures:
     Failure/Error: params: { file: fixture_file_upload('files/aaa.zip', 'application/zip') },
     
     ArgumentError:
       the directory '/app/spec/fixtures/fixtures/' does not contain a file named 'files/aaa.zip'
```

```diff_ruby:rubocop自動変換された箇所（spec/rails_helper.rb）
- config.fixture_path = "#{::Rails.root}/spec/fixtures"
- config.file_fixture_path = "#{::Rails.root}/spec/fixtures"
+ config.fixture_path = "#{Rails.root.join('spec', 'fixtures', 'fixtures')}"
+ config.file_fixture_path = "#{Rails.root.join('spec', 'fixtures', 'fixtures')}"
```

## DateTime#to_sでWARNINGがでる
RSpecを実行すると以下のWARNINGがでました。詳細は以下の記事より。ただし、Rails 7.1系までアップロードすると解決できます。今回は7.1.4にしたので解決できました。

https://qiita.com/SoarTec-lab/items/d2478996f2864f11c4ac

```text
DEPRECATION WARNING: Using a :default format for DateTime#to_s is deprecated. Please use 
DateTime#to_fs instead. If you fixed all places inside your application that you see this 
deprecation, you can set `ENV['RAILS_DISABLE_DEPRECATED_TO_S_CONVERSION']` to `"true"` in the 
`config/application.rb` file before the `Bundler.require` call to fix all the callers outside 
of your application.
```

## psych::disallowedclass「tried to dump unspecified class」 が出る

psychのバージョンを下げて対応

## DEPRECATION WARNING: Setting action_dispatch.show_exceptions to false is deprecated. Set to :none instead. が出る
以下の記事の通りです。Rails 7.1系から`action_dispatch.show_exceptions = false`は非推奨になりました。同様の動作をするのは`:none`ですが、以下の記事の通り、`:rescuable`をrailsは推奨しています。ここでは、Rspecの結果に影響がなかったため、`:rescuable`を指定しました。

https://picolab.dev/2023/12/06/rails-7-1_action_dispatch-show_exceptions/

## Calling `DidYouMean::SPELL_CHECKERS.merge!(error_name => spell_checker)' has been deprecated. Please call `DidYouMean.correct_error(error_name, spell_checker)' instead. が出る

`bundle update --bundler` を実行すればよい

https://qiita.com/vaza__ta/items/1e7a780499b5effbfd65

## DEPRECATION WARNING: Support for `config.active_support.cache_format_version = 6.1` has been deprecated and will be removed in Rails 7.2.がでる

## production.logが出力されない
`rails app:update`で更新した設定ファイルの中に以下が追加されていた。削除して完了

```diff_ruby
- # Log to STDOUT by default
- config.logger = ActiveSupport::Logger.new(STDOUT)
-     .tap  { |logger| logger.formatter = ::Logger::Formatter.new }
-     .then { |logger| ActiveSupport::TaggedLogging.new(logger) }
```

## ELBからのヘルスチェックがNGになる

ELBからEC2のヘルスチェックは80番で独自のパスにアクセスしてチェックしていたが、nginxが301を返していた。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192137/b6f23a2d-23c1-ca54-6f22-d0aa2e761d59.png)

Rails 7.1系からforce_ssl = trueがデフォルトになっていたためSSLを使わない通信をエラーにしていたため。falseに変更して対応した。
https://techracho.bpsinc.jp/hachi8833/2023_07_04/131866