rails db:system:changeコマンドはSpring経由で実行するとinvalid optionで失敗する

# はじめに

`rails db:system:change`コマンドはRails6で追加されたコマンドです。
このコマンドにより、Railsが使用するDBをPostgreSQLやMySQL等に簡単に変更できるはずなのですが、試しに実行してみたところ、以下のようなエラーになりました。

```
% rails db:system:change --to=postgresql
Running via Spring preloader in process 15906
invalid option: --to=postgresql
```

調査したところ、回避方法や原因がわかったので以下に説明します。

# 回避方法

Springを無効にすることで回避できます。
SpringはRails6の場合、development環境において標準で有効になっています。
Springにはrailsやrakeコマンドの実行時間を短縮する効果がありますが、[マシンスペックの向上に対してその恩恵が少なくなったと判断され](https://github.com/rails/rails/pull/42997)、Rails7では標準で無効となりました。
したがって、多くの場合無効にしても問題にならないと思います。

簡単にSpringを無効にする方法は以下です。

1: Gemfileでspringをコメントアウトします。
  ```rb
  group :development do
    # Access an interactive console on exception pages or by calling 'console' anywhere in the code.
    gem 'web-console', '>= 4.1.0'
    # Display performance information such as SQL time and flame graphs for each request in your browser.
    # Can be configured to work on production as well see: https://github.com/MiniProfiler/rack-mini-profiler/blob/master/README.md
    gem 'rack-mini-profiler', '~> 2.0'
    gem 'listen', '~> 3.3'
    # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring
    # gem 'spring' # ← ここ
  end
  ```
2: `bundle install`を実行します。

`rails db:system:change`コマンドの実行後、再度Springを使いたい場合は、コメントアウトを戻して`bundle install`すれば使えます。

# 原因

[GitHubのissue](https://github.com/rails/rails/issues/34710#issuecomment-1140257170)で報告したのですが、直接的な原因はSpringの[この修正](https://github.com/rails/spring/commit/b85f41be7eed1533c88c38cf1e72628a249ab8e4)です。
全てのdbコマンドに対してrakeが呼び出されるようになっていました。
したがって、以下のコマンドのエラーが表示されていたということになります。

```
% rake db:system:change --to=postgresql
invalid option: --to=postgresql
```

`db:system:change`は他と違ってrake taskではないためエラーになります。

なお、問題の修正が入ったのはspring gemのv3.1.1からなので、v3.1.0までなら本現象は発生しません。

# 今後の対処

Spring側を修正する方針になったので、[PR](https://github.com/rails/spring/pull/679)を出しておきました。
したがって、今後Spring gemが更新されると修正される見込みです。

ちなみに、[この修正](https://github.com/rails/spring/commit/b85f41be7eed1533c88c38cf1e72628a249ab8e4)にはもう１個問題があって、`rails`コマンドを引数なしで実行すると以下のように`NoMethodError`で失敗します。

```log
% rails
Traceback (most recent call last):
	12: from bin/rails:2:in `<main>'
	11: from bin/rails:2:in `load'
	10: from /Users/inayuky/work/rails-postgre/bin/spring:7:in `<top (required)>'
	 9: from /Users/inayuky/work/rails-postgre/bin/spring:7:in `tap'
	 8: from /Users/inayuky/work/rails-postgre/bin/spring:10:in `block in <top (required)>'
	 7: from /Users/inayuky/.rbenv/versions/2.7.5/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:83:in `require'
	 6: from /Users/inayuky/.rbenv/versions/2.7.5/lib/ruby/2.7.0/rubygems/core_ext/kernel_require.rb:83:in `require'
	 5: from /Users/inayuky/.rbenv/versions/2.7.5/lib/ruby/gems/2.7.0/gems/spring-4.0.0/lib/spring/binstub.rb:11:in `<top (required)>'
	 4: from /Users/inayuky/.rbenv/versions/2.7.5/lib/ruby/gems/2.7.0/gems/spring-4.0.0/lib/spring/binstub.rb:11:in `load'
	 3: from /Users/inayuky/.rbenv/versions/2.7.5/lib/ruby/gems/2.7.0/gems/spring-4.0.0/bin/spring:49:in `<top (required)>'
	 2: from /Users/inayuky/.rbenv/versions/2.7.5/lib/ruby/gems/2.7.0/gems/spring-4.0.0/lib/spring/client.rb:30:in `run'
	 1: from /Users/inayuky/.rbenv/versions/2.7.5/lib/ruby/gems/2.7.0/gems/spring-4.0.0/lib/spring/client/command.rb:7:in `call'
/Users/inayuky/.rbenv/versions/2.7.5/lib/ruby/gems/2.7.0/gems/spring-4.0.0/lib/spring/client/rails.rb:25:in `call': undefined method `start_with?' for nil:NilClass (NoMethodError)
```

これもSpringを無効にすることで回避できます。
こちらは[この修正](https://github.com/rails/spring/pull/667)により、将来直るはずです。

なお、Rails7だと標準ではSpringが無効になっていますが、Springを有効にするとRails7でもこれらの現象は発生します。

# 参考

https://github.com/rails/rails/issues/34710

https://github.com/rails/spring/issues/678

https://github.com/rails/spring/pull/679

https://qiita.com/ryohashimoto/items/f5382478c78f296d8291#springの非標準化