Rails unable to autoload constant from file despite being defined in that file

前端 未结 3 1741
傲寒
傲寒 2021-02-18 23:42

This is a tricky one to explain. I have a module in another module namespace like so:

# app/models/points/calculator.rb
module Points
  module Calculator
    de         


        
相关标签:
3条回答
  • 2021-02-19 00:11

    Calculator should be a class to be autoloaded correctly

    module Points
      class Calculator
      ...
      end
    end
    
    0 讨论(0)
  • 2021-02-19 00:12

    Rails augments the constant lookup mechanism of ruby.

    Constant lookup in Ruby:

    Similar to method missing, a Module#constant-missing is invoked when a reference to a constant fails to be resolved. When we refer to a constant in a given lexical scope, that constant is searched for in:

    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.
    

    When we refer to a constant, Ruby first attempts to find it according to this built-in lookup rules.

    When ruby fails to find... rails kicks in, and using its own lookup convention and its knowledge about which constants have already been loaded (by ruby), Rails overrides Module#const_missing to load missing constants without the need for explicit require calls by the programmer.

    Its own lookup convention?

    Contrasting Ruby’s autoload (which requires the location of each autoloaded constant to be specified in advance) rails following a convention that maps constants to file names.

    Points::Calculator # =>points/calculator.rb
    

    Now for the constant Points::Calculator, rails searches this file path (ie 'points/calculator.rb') within the autoload paths, defined by the autoload_paths configuration.

    In this case, rails searched for file path points/calculator in its autoloaded paths, but fails to find file and hence this error/warning is shown.

    This answer is an abstract from this Urbanautomation blog.

    Edit: I wrote a blog about Zeitwerk, the new code reloader in Rails. Check it out at -> https://blog.bigbinary.com/2019/10/08/rails-6-introduces-new-code-loader-called-zeitwerk.html

    0 讨论(0)
  • 2021-02-19 00:19

    If someone is having this issue in rails 6 which has zeitwerk autoloader,

    Change ruby constant lookup back to classic in your application.rb

    # config/application.rb
    #...
    config.autoloader = :classic
    #...
    

    Read more details here Rails Official Guides

    0 讨论(0)
提交回复
热议问题