Inconsistent “LoadError” behavior with 'lib' namespacing/autoloading

前端 未结 5 1762
情书的邮戳
情书的邮戳 2020-12-24 07:19

We have just created a new file in \'lib\' that has spawned a series of headaches involving load errors.

/lib/response_set.rb:

module MyCompany
  cla         


        
相关标签:
5条回答
  • 2020-12-24 07:39

    I've suffered from the very same problem with namespaced classes being autoloaded incorrectly. This is the clue to solve it (from Brendan's answer):

    Since our autoload_paths included both lib and lib/**, Rails pulled in all the files from all the subdirectories under lib. Unfortunately, it appears to ignore the implied namespace when loading from subdirectories. It expected foo/base.rb to define Base vs. Foo::Base. That seems to be the core flaw: load_missing_constant invokes search_for_file which returns any file whose name matches (e.g., in my example, foo/base.rb was returned as it matched base.rb).

    And I've solved it by moving all my namespaced classes, named Events::Something, into app/components/events/* and creating a file app/components/events.rb with the following content:

    %w(file1 file2 ...).each do |file|  
      require "events/#{file}"
    end
    

    And while this is a little bit manual, it works both for application, console and test modes.

    0 讨论(0)
  • 2020-12-24 07:46

    We had a similar issue which, after digging, turned out to be caused by the changes in Rails 3.x and autoload_paths.

    Our case appeared only in test (RAILS_ENV=test). When Rails was loading the controllers, it scrambled about looking for each controller's matching model (due to a ActionController::Base.wrap_parameters set in an initializer). Eventually it wound down to the method mentioned above (load_missing_constant). Since our autoload_paths included both lib and lib/**, Rails pulled in all the files from all the subdirectories under lib. Unfortunately, it appears to ignore the implied namespace when loading from subdirectories. It expected foo/base.rb to define Base vs. Foo::Base. That seems to be the core flaw: load_missing_constant invokes search_for_file which returns any file whose name matches (e.g., in my example, foo/base.rb was returned as it matched base.rb).

    It's hard to say if this is an error in Rails - in that it violates the namespace-to-directory mapping assumed by Ruby - or a misuse of autoload_paths.

    We have worked around this for now by removing lib/** from our autoload_paths and adding the necessary require statements to application.rb.

    0 讨论(0)
  • 2020-12-24 07:48

    I looked into the rails source and there is a

    if file_path && ! loaded.include?(File.expand_path(file_path)) # We found a matching file to load
      require_or_load file_path
      raise LoadError, "Expected #{file_path} to define #{qualified_name}" unless local_const_defined?(from_mod, const_name)
      return from_mod.const_get(const_name)
    elsif ...
    

    clause in load_missing_constant method. I may guess that as require_or_load is called before raise, this might be a reason that on the second call in your example there is no error...

    It would be interesting to see a minimal example where two files with identical structure behave differently. In your place i would make a copy of the application and would keep removing parts from it while the inconsistent behavior is present to see the minimal inconsistent example.

    P.S. I have submitted a similar question here: http://www.ruby-forum.com/topic/2376956

    0 讨论(0)
  • 2020-12-24 07:55

    Another point worth to notice is that whether you have the correct path in services folder.

    By correct path, I mean

    engine_name/app/services/engine_name/your_service.rb

    I have accidentally forgot engine_name folder inside services, and got this strange behaviour.

    0 讨论(0)
  • 2020-12-24 08:02

    Was pointed in the correct direction by Brendan, check your autoload_paths. I had a similar error and this was the culprit for me in application.rb :

    config.autoload_paths += Dir["#{Rails.root}/app/models/[a-z]*"]
    

    My app was not happy once I started using modules for the models along with having sub-directories. I changed mine to autoload just the non-module directories :

    config.autoload_paths += Dir["#{Rails.root}/app/models/aaaaaaaaa"]
    config.autoload_paths += Dir["#{Rails.root}/app/models/bbbbbbbbb"]
    
    0 讨论(0)
提交回复
热议问题