0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

キーワード引数と通常のハッシュ引数を明示的にしろ(Ruby3系)

Last updated at Posted at 2025-05-05

前置き

とある Ruby on Rails のプロダクトを Heroku で動かしていたですが、Heroku の stack を上げないとサーバーが止まってしまうから上げろという警告がデプロイのたびに一年弱表示されていました。
しかし、このプロダクトは Ruby 2.7.6 で、stack のアップデートには Ruby 3系がマストでした…
Ruby のアップデートすら面倒で、この際インフラを Heroku から GCP に移行してしまおう!という話になっておりました。ですが、後回しにしまくっていたら期限が目前に…😱

そこで、取り急ぎ Ruby を 2.7.6 -> 3.1.4 にアップデートすることとしました。

環境

  • Ruby: 2.7.6
  • Ruby on Rails: 6.1.4

UPDATE Ruby の手順

  1. 前提として、Rails のバージョンはそのままにしたい(まず Ruby による影響だけを解消するためひとまず Ruby だけをアップデートする)ので、Rails 6.1.4 で動く Ruby のバージョンを決めます。
    Rails の公式ドキュメントなど漁りましたが対応表のようなものが見当たらず、こちらを拝見して少なくとも Ruby 3.1.4 で Rails 6.1.4 は動くことを予想し、 Ruby 3.1.4 へのアップデートを決めました。
    https://mrradiology.hatenablog.jp/entry/2023/09/29/095743

  2. gem の更新と bundle install
    ruby version 依存により1, 2個ほどエラーが出ていました。デバッグ関連の gem が原因で、しばらく使ってなかったものなので、一旦削除することにして、クリアしました。

  3. docker でビルドしてみる。
    これで落ちてしまって、少し時間を取られました。多分キャッシュが残っているなどかと思います。docker compose build --no-cache , docker compose up --remove-orphans とかで治った気がします。

  4. CIチェック
    これで Pull Request を作ったのですが、CIが落ちていました…
    と思ったら、RSpecが大量に落ちていたのです。。!!!!!!
    スクリーンショット 2025-05-06 0.04.20.png
    (次項に続く・・・

Ruby 2系 -> 3系 の大きな変更

前項4で、テストが大量に落ちていた原因です。

スクリーンショット 2025-05-06 0.08.49.png


とのことらしい…!!

✅ つまり、Ruby 3.0 では、キーワード引数と通常のハッシュ引数が厳密に区別されるようになりました。
この変更が原因で、多くのテストや既存のコードが壊れる事例が頻発していました。

Ruby 2.7 まではどうだったか?

Ruby 2.7 では、以下のような「ハッシュをキーワード引数として渡す」コードも警告を出しつつ許容されていました。

def greet(name:, age:)
  puts "Name: #{name}, Age: #{age}"
end

params = { name: "Alice", age: 30 }

greet(**params) # ✅ OK
greet(params)   # ⚠️ 警告(deprecated)だが動く

これは Ruby 内部で params がキーワード引数に「暗黙的に変換」されていたからです。

Ruby 3.0 以降では?

Ruby 3.0 では、この暗黙変換が完全に廃止されたため、上記のような書き方はエラーになります。

def greet(name:, age:)
  puts "Name: #{name}, Age: #{age}"
end

params = { name: "Alice", age: 30 }

greet(**params) # ✅ OK
greet(params)   # ❌ エラー

このように、キーワード引数として渡したい場合は ** 展開を明示する必要があります。

一方で、メソッド側が通常の引数(位置引数)を期待している場合も以下のようになります。

def some_method(params)
  puts params.inspect
end

some_method({ foo: "bar" })   # ✅ OK

some_method(**{ foo: "bar" }) # ❌ ArgumentError: wrong number of arguments (given 0, expected 1)

まとめ

バージョンアップは面倒だし、Ruby も Rails も破壊的なアップデートをされることがあるので、大変…
できるだけ定期的にアップデートするのがいいかもですね、、

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?