ActiveRecord を使っていて NoMethodError: undefined method `new' for BigDecimal:Class と言われたら

ActiveRecord でクエリを実行した結果 BigDecimal 型のインスタンスを組み立てるようなものが含まれている場合、使っている Ruby のバージョンや他ライブラリのバージョン次第でこのようなエラーが出ます。

NoMethodError: undefined method `new' for BigDecimal:Class 

先日詳細知らされていない状態でこのエラーを渡されたのでとりあえず調べてみると以下の Qiita の記事がトップに出てきました。

qiita.com

結論から言うとこの記事に書いてある対処方法は端的に言ってよろしくないのでやめましょう。

そもそもこのエラーが出る問題の原因として BigDecimal の扱いが、とあるバージョンから変わっているからです。 バージョンによる BigDecimal の取扱方の違いは README.md にちゃんと書いてあります。

github.com

前述の Qiita の記事の何が良くないかって、古いバージョンに固定して対処していることなんですよね。 しかもこうしろと書いてある。

gem 'bigdecimal', '1.3.5'

次に BigDecimal の README.md に書いてある説明を引用します。

version characteristics Supported ruby version range
3.0.0 You can use BigDecimal with Ractor on Ruby 3.0 2.5 ..
2.0.x You cannot use BigDecimal.new and do subclassing 2.4 ..
1.4.x BigDecimal.new and subclassing always prints warning. 2.3 .. 2.6
1.3.5 You can use BigDecimal.new and subclassing without warning .. 2.5

1.3.5 は確かに BigDecimal.new が使えるので一見大丈夫そうに見えるんですが、これサポートされる Ruby バージョンが 2.5 までなんですよね。

2.5、EOL date: 2021-03-31 なんですよ...。

じゃあどうするのがいいかと言うと、この Qiita の記事にはどこでどんな形でエラーが発生しているかが明記されていないので、自分が調べた限りの想像ですが。

(そもそもちゃんとエラーの詳細を記事に書きましょうよ...)

mysql2 のバージョンが古いのが原因です。

github.com

もしこのエラーが発生して、手元の mysql2 のバージョンが < 0.5.0 ならこれを疑いましょう。 rails new すると mysql2 のバージョンが固定された Gemfile が生成されるからバージョン上げるの放置してて Ruby のバージョン上げたら踏んだパターンなのではないですかね。

この記事執筆時点で 2.5 の EOL が目前なので、これ踏む人増えそうなので書き残しておきます。