これは説明するのが難しいものです。次のような別のモジュール名前空間にモジュールがあります。
# app/models/points/calculator.rb
module Points
module Calculator
def self.included(base)
base.send(:include, CommonMethods)
base.send(:include, "Points::Calculator::#{base}Methods".constantize)
end
end
end
したがって、他のクラスでは、私がする必要があるのは次のとおりです。
class User
include Points::Calculator
end
Application.rbでこのディレクトリを自動ロード可能に指定しました...(Railsはモデルを介して再帰すると思いますが...)
config.autoload_paths += Dir[ Rails.root.join('app', 'models', "points") ]
開発環境では、すべてが正常に機能します。テスト(および本番環境)を実行すると、次のエラーが発生します。
Unable to autoload constant Points::Calculator, expected /Users/pete/work/recognize/app/models/points/calculator.rb to define it (LoadError)
私は実際にここでのアドバイスに従って問題を修正しました: Railsが開発モードでモジュールをアンロードしないようにします application.rbでcalculator.rbを明示的に要求します。
しかし、なぜこれが起こっているのですか?
ActiveSupportのdependencies.rbファイルにデバッグ出力を貼り付けたところ、このファイルが2回必要であることがわかりました。初めて必要になったとき、定数が実際にロードされていることがわかります。
しかし、2回目は、Railsが知る限り定数がアンロードされましたが、実際のrequireが呼び出されると、Rubyはすでに必要であることがわかっているため、Rubyはfalseを返します。次に、Railsは、定数がまだ存在せず、Rubyがファイルを「再要求」しなかったため、「定数を自動ロードできません」エラーをスローします。
なぜこれが起こっているのかを誰かが明らかにすることができますか?
Railsは、Rubyの定数ルックアップメカニズムを強化します。
Rubyでの定数ルックアップ:
method missing
と同様に、定数への参照が解決されない場合、Module#constant-missing
が呼び出されます。特定の字句スコープで定数を参照すると、その定数は次の場所で検索されます。
Each entry in Module.nesting
Each entry in Module.nesting.first.ancestors
Each entry in Object.ancestors if Module.nesting.first is nil or a module.
定数を参照する場合、Rubyは、最初にこの組み込みのルックアップルールに従って定数を見つけようとします。
Rubyが見つからない場合... Railsキックイン、および使用its own lookup convention
および(Rubyによって)すでにロードされている定数に関する知識、RailsはModule#const_missing
をオーバーライドして、欠落している定数をロードせずにプログラマーによる明示的なrequire呼び出しの必要性。
独自のルックアップ規則?
対照的なRubyのオートロード(オートロードされた各定数の場所を事前に指定する必要があります)Rails定数をファイル名にマップする規則に従い、.
Points::Calculator # =>points/calculator.rb
ここで、定数Points :: Calculatorについて、Railsは、autoload_paths
構成で定義された自動ロードパス内のこのファイルパス(つまり、 'points/calculator.rb')を検索します。
この場合、Railsはオートロードされたパスでファイルパスpoints/calculator
を検索しましたが、ファイルが見つからないため、このエラー/警告が表示されます。
この答えはこれからの要約です rbanautomationブログ 。
編集:Railsの新しいコードリローダーであるZeitwerkについてブログを書きました。 -> https://blog.bigbinary.com/2019/10/08/Rails-6-introduces-new-code-loader-called-zeitwerk.html で確認してください。
Calculator
は、正しくオートロードされるためにclassである必要があります
module Points
class Calculator
...
end
end