Rails class loading skips namespaced class when another class of same name in root namespace is loaded

后端 未结 2 785
长情又很酷
长情又很酷 2021-01-05 06:00

I have two namespaces, each with its own controller and presenter classes: Member::DocumentsController Member::DocumentPresenter Guest::Docum

相关标签:
2条回答
  • 2021-01-05 06:02

    I think in 3 solutions if you want to mantein the name, one is your second solution.

    1) explicitly require appropriate presenter files in controller files

    2) Execute the full environment class path, like:

    class Guest::DocumentsController < ActionController::Base
        def show
            Guest::DocumentPresenter.new(find_document)
        end
    end
    

    3) Create a file on initialize directory and execute require manually (the worst options :S)

    0 讨论(0)
  • 2021-01-05 06:20

    You are correct in your assumptions - If you do not specify namespace, Ruby starts from current namespace and works its way up to find the class, and because the namespaced class is not autoloaded yet, the ::DocumentPresenter is found and autoloader does not trigger.

    As a solution I would recommend renaming ::DocumentPresenter to DocumentPresenterBase, because this protects you from bugs when you forget namespacing or explicit requiring somewhere.

    The second option to consider would actually be using specific namespaced classnames all over the place, but this suffers from bugs when you accidentally forget to namespace some call.

    class Guest::DocumentsController < ActionController::Base
      def show
        Guest::DocumentPresenter.new(find_document)
      end
    end 
    

    Third option would be your second - explicitly require all the classes in initializer beforehand. I have done this with Rails API which receives embedded models in JSON and Rails tends to namespace them when the actual models are not loaded yet.

    Option 3.5 You could probably trick autoloader to do the heavy lifting (though, this might seem more like a hack):

    class Guest::DocumentsController < ActionController::Base
    
      # trigger autoload
      Guest::DocumentPresenter
    
      def show
        # This should refer Guest::DocumentPresenter
        DocumentPresenter.new(find_document)
      end
    
      def show
        # As will this
        DocumentPresenter.new(find_document)
      end
    end 
    

    Still the cleanest would be to rename the base class.

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