Rails4で`whiny_nils`オプションが廃止された理由

こんにちは、hachi8833です。

TechRacho記事「Ruby2.0でnil.object_idの値が4から8に変わった理由」の元記事で触れられていたRailsの昔のオプションwhiny_nilsについて別途調べてみました。

参考

whiny_nilsオプションはRails 4で廃止された

2008年に公開された上述のBigBinary記事「Why the id of nil is 4 in Ruby」では、Railsのconfig.whiny_nilsオプションについて言及されています。

この設定オプションを調べてみると、Rails 4の段階でdeprecation warningが表示されるようになっていました

DEPRECATION WARNING: config.whiny_nils option is deprecated and no longer works. (called from block in at /Users/adam/src/sandbox/screencast/config/environments/development.rb:10)
config.eager_load is set to nil. Please update your config/environments/*.rb files accordingly:

さらにRails 4.1で削除され、warningも表示されなくなりました(参考: Rails 4.1リリースノート)。

なおwhinyは「{形} : 泣き言を言う、めそめそした、機嫌の悪い、不機嫌な」だそうです。いかにもnilとの語呂合わせですね。

whiny_nilsが廃止された理由

Rails 4でwhiny_nilsが廃止された理由を調べてみました。

nilのオブジェクトIDについては別記事「Ruby2.0でnil.object_idの値が4から8に変わった理由」を参照してください。

ググっただけではそれらしい情報が見当たらなかったので、RailsのGitHubリポジトリを辿ってalindeman/upgradingtorails4のActiveRecordの更新に関する記述を見つけました。

Rails 3から4への移行期に相当します。該当箇所の大意を以下にメモしてみました。

whiny_nils

Rails 4で廃止されたwhiny_nilsは、nilidメソッドが送信された場合に警告を表示するためのオプションでした。たとえば@modelが初期化されていない状態で@model.idを取ろうとしたときに警告されます。Rubyでは初期化されていないインスタンス変数はnilを返します。

Ruby 1.9.3より前は、Objectは#idを受信できました。そしてnilもObjectに属します。特にやっかいだったのは、Ruby 1.9.3より前のnil.idが実装上の理由から4を返していたことです。このあたりについて詳しくは、Railsのベテラン開発者にお尋ねください。

ありがたいことに、Ruby 1.9.3以降はObjectが#idを受信しないようになりました。つまりwhiny_nilsオプションはもう必要ないのですnil.idを実行すれば普通にNoMethodErrorが表示されます。まぎらわしい警告は表示されません。

Railsでは今後、whiny_nilsオプションがオンになっている場合に非推奨の警告が表示されるようになります。この警告を非表示にしたい場合は、config/environments/development.rbconfig/environments/test.rbからconfig.whiny_nilsを有効にしている行を削除してください。
alindeman/upgradingtorails4の「whiny-nils」より

idメソッドはRailsのActiveRecordモデルで多用されますが、1.9.3以前のRubyにObject#idが実装されていたためにモデルオブジェクトのidnilの場合にObject#idが応答してnil.idの値である4を返してしまうという問題があったことが推察されます。

モデルオブジェクトがnilなのにエラーにならないと適切に処理できないので、それを回避するために当時のRailsにconfig.whiny_nilsオプションが導入されていたのですね。

試してみると、Ruby 1.8の時点でもnil.idを実行すると非推奨の警告が表示されます。Rubyの#idという標準メソッド名が以前から問題視されていたことがうかがえます。

Ruby 1.9.3で#id#object_idに変更した理由がRailsのActiveRecordのためなのか、Sinatraなど他のフレームワークでも不都合が生じていたからなのかはさらに調べないとわかりませんが、whiny_nils廃止の理由がこれでわかりました。

RailsガイドのRails アップグレードガイドでは以下のとおりRuby 2.0が推奨されていますが、その理由のひとつがobject_idに移行したRuby 2.xが必要だからということですね。

Rails 4ではRuby 2.0が推奨されます。Ruby 1.9.3以上が必須です。

関連記事(BigBinaryシリーズ)

Ruby on RailsによるWEBシステム開発、Android/iPhoneアプリ開発、電子書籍配信のことならお任せください この記事を書いた人と働こう! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833

コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。
これまでにRuby on Rails チュートリアル第2版の半分ほど、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れてそれぞれ一部を翻訳。
かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。
実は最近Go言語が好き。
仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

BPSアドベントカレンダー

週刊Railsウォッチ

インフラ

BigBinary記事より

ActiveSupport探訪シリーズ