これは説明するのが難しいです。次のような別のモジュール名前空間にモジュールがあります。
# 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 は既にそれが要求されていることを知っているので false を返します。その後、定数がまだ存在せず、ruby がファイルを「再要求」しなかったため、Rails は「定数を自動ロードできません」というエラーをスローします。
なぜこのようなことが起こるのか、誰か説明できますか?
ベストアンサー1
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 の autoload (各自動ロード定数の場所を事前に指定する必要がある) とは対照的に、rails は定数をファイル名にマッピングする規則に従います。
Points::Calculator # =>points/calculator.rb
ここで、定数 Points::Calculator の場合、Rails は構成で定義された自動ロード パス内でこのファイル パス (つまり 'points/calculator.rb') を検索しますautoload_paths
。
この場合、Rails はpoints/calculator
自動ロードされたパス内でファイル パスを検索しましたが、ファイルが見つからなかったため、このエラー/警告が表示されます。
この回答は、このアーバンオートメーションブログ。
編集: Rails の新しいコードリローダー Zeitwerk についてブログを書きました。こちらをご覧ください ->https://blog.bigbinary.com/2019/10/08/rails-6-introduces-new-code-loader-called-zeitwerk.html