ユニファ開発者ブログスマートフォン用の表示で見るユニファ開発者ブログユニファ株式会社システム開発部メンバーによるブログです。Railsこんにちは、システム開発部のちょうです。今回はあるエラーから1つ小さいなライブラリを作った話について共有したいと思います。active!」というエラーに遭遇しまして、一回あったらRailsアプリを再起動しないといけない状態になります。回数が少ないですが、開発の邪魔になるので、少し調べました。本番環境は出ない(自分の経験でも開発環境以外見たことはない)エラーメッセージによると、モジュールは削除されましたがまだ使われてる(正直ピンとこない)ひとまず、解決策はわかったので、使ったら元々エラーになった箇所も確実に直りました。別のところで同じエラーで怒られました。すべてのクラス名をフルネームで書き直すのは煩雑な作業になるから、やはり根本的な原因を探さないといけないと思いました。エラーメッセージの一部をキーワードとしてプロジェクトとライブラリ内で検索してみたら、ActiveSupport::Dependenciesのソースコードでこのエラーメッセージが見つかりました。endendbreakpointを入れて開発環境で何回debugしてみましたが、残念ながら、一回も再現できませんでした...一方、エラーメッセージでもっと調べた結果、このブログが見つかり、再現できる方法が分かりました。Customer.newActiveSupport::Dependencies.clearcustomer.moneyまとめてみると、その手順はインスタンス作成ActiveSupport::Dependenciesがクリアされ(開発環境ではコントロールやモデルファイルを弄るとかで発生する)インスタンスのメソッドで別のクラスを呼び出すになります。確かに、自分が開発しているRailsアプリでは、initializerにクラスのインスタンスを作るコードがありました。Guidesによると、initializerにインスタンスを初期化はおすすめしません。(正確にいえば、autoloadパスにあるクラスのインスタンスです。ライブラリのクラスは対象外です。)つまり、根本的な解決策はinitializerにインスタンスを作成しないってことでしょうか。point、つまりXXX.instanceを使えばいいのでしょうか。開発環境のautoloadでinitializerにインスタンスを作れないのはあまり納得できないです。他の環境なら普通に使えますし、これによってXXX.instanceだらけなコードになるのもよろしくないと思います。::Fooという解決策がいますので、他の解決策もあるはずです。Customer.newcustomer.moneyActiveSupport::Dependenciesがクリアされる時、同時にインスタンスを作り直します。この仕組みを実現するには、ActiveSupport::Dependenciesがクリアされるタイミングインスタンスを作成するロジックを持ってないといけないが必要になります。一番はとくに複雑ではないです。Railsでは、ActionDispatch::Reloaderという機能が使えます。ActiveSupport::Dependenciesがクリアされた後実行されます。endendもう一つの機能は自分で書こうと思います。Customer#<Money:0x007fd72205db78>ObjectContainer.reload!はActionDispatch::Reloader.to_prepareに追加されれば、自動的にインスタンスを作り直します。この方法は::Fooよりすこしコードを書く必要がありますが、インスタンスは一元管理できるので、サービスなどに大きなメリットがあると思います。おまけそもそもそのエラーはなぜ出たのか、なんで::Fooが解決できるのか、その答えはActiveSupport::Dependenciesのautoloadにあります。これはActiveSupport::Dependenciesを基いてエラーを再現するコードです。:Bar)bar.runActiveSupport::Dependenciesのautoload機能はmoduleのconst_missingなどを利用して、動的にソースコードファイルをロードする仕組みです。理解すべきはA::Bを解析するために、AA::Bの順番でやります。Aがロードされない場合は、A::Bのロードは不正なリクエストと見なされます。クラスのインスタンスはクラスがremove_constされても消滅しません。ここは微妙なところですね。クラスがないのに、インスタンスが存在しています。bar.runを実行する時、const_missingで入力したconst_nameはFoo、そしてモジュール(self)はBar、つまりBar::Fooを探しています。autoloadが検索する時、Bar::FooFooの順番でロードしてみます。active!というエラーが発生するはずです。ここではBarという定数が削除されて、でもBarのインスタンスが残って、Barのインスタンスメソッドで別のクラスを呼び出そうとすると、Bar::XXXでロードし、Barがないままエラーになってしまいました。activeというのはインスタンスです。ちなみに、::Foo.newで書くと、最初からFooでロードするので、Barのクラスがロードされなくてもエラーになりません。今回はエラーをきっかけにautoloadをすこし勉強しましたが、皆さんにも参考になれば幸いです。最近、鼻づまりがひどいWebエンジニアのほんまです。Fargate)で運用する際のログ設定で工夫した点こんにちは、Webエンジニアの本間です。比較演算子の左右とコメント...2018-02-05CsvBuilderとExcelBuilderを作ってみましたこんにちは、システム開発部のちょうです。Detection月別アーカイブスターをつけました引用をストックしましたストック一覧を見る閉じる引用するにはまずログインしてくださいログイン閉じる引用をストックできませんでした。再度お試しください閉じる限定公開記事のため引用できません。