Ktouth Brand. on Web

け〜くんこと K.Ktouth のだらだらした日常と突発的に作るプログラムや読み物とかの雑多サイト



[2007年10月10日]

混ぜるな危険! autoloadとrequire

2007年10月11日 11:48更新 筆者:K.Ktouth

Ruby on Rails入門―優しいRailsの育て方(AA)

昨日、間違って環境破壊をしてしまった遠因は、ちょっとした原因がつかめないトラブルにあったんです。
昨日までは普通に通っていたテストがいきなり失敗するように、と言う。

EntryとTagモデルは、Taggingジョインモデルを経由する多対多関連です。
TaggingモデルはEntryとTag両モデルから:dependent => :destoryオプション付きで接続され、片方が消えると巻き込まれて削除されます。
Taggingモデルからは:counter_cache => :taggings_countでカウンターキャッシュを指示しています。

で、railsを1.2.4にバージョンアップさせている途中でこのカウンターキャッシュが正しい値になっていない事がテストで明らかに。
もちろんこの3モデルは先日から触ってません。
その後、Taggingモデルが「2度削除されている」ところまでは確認したのですが……そもそもなんの定義も変更していないのにこうなってしまっていたので、ドコを触ればいいのか全くわからず。

悩む事1時間。
ふてくされて寝ました(ぉ

ところが、「わからないときは一度机から離れろ、一眠りすれば解決案も浮かぶさ」と昔からよく言われているように。
目覚めと同時に原因判明

その日、 /lib/entry フォルダに配置していた Entry::SearchBuilder というヘルパークラスのテストで(今まで出ていなかった)「Entryという定数が見つからない」というエラーが出たんです。
おそらく1.2.4にアップした事による警告の追加でしょう。
で、そのファイルの先頭に……

require 'entry'

と書いていたんですよ。
まさかコレが原因だったとはびっくり
どーもautoloadで読み込まれたライブラリはrequireで読み込むライブラリの重複チェックに引っかかっていないのか、Entryモデルのファイルを2度読み込んでいた模様。
railsの魔法、has_menyによる関連定義が2度実行され、after_destroyの処理が2重に定義された……というのが真相でした。

いったん原因がわかれば後は簡単。

Entry

定義を一度参照すればautoload処理も働くので、requireは不要だったのです。
autoloadで呼ばれる事が前提のスクリプトをrequireしてはならない。
混ぜるな危険、まさにそんな教訓を得ました(笑)


余談。
舞波さんのところで公開されたこのプラグイン、めっちゃ便利そうすき

本日のリンク元
アンテナ
その他のリンク元
検索