Rails中控制器的嵌套命名空间

the*_*ter 7 ruby ruby-on-rails ruby-on-rails-4

我重构了我的rails应用程序,对于我创建控制器的每个子资源都是相应的命名空间.

api/v1/app/controller/manager.rb
api/v1/app/controller/manager/user.rb
api/v1/app/controller/manager/controller.rb
api/v1/app/controller/admin.rb
api/v1/app/controller/user.rb
api/v1/app/controller/controller.rb
Run Code Online (Sandbox Code Playgroud)

manager命名空间下的用户资源的类定义如下所示

class Api::V1::Manager::UserController < ApplicationController
Run Code Online (Sandbox Code Playgroud)

该控制器可通过routes.rb访问:

 resources :manager , only: [:show ] do
   resources :user, only: [:index], controller: 'manager/user'
 end
Run Code Online (Sandbox Code Playgroud)

产生

/api/v1/manager/:manager_id/user(.:format)       api/v1/manager/manager#index {:format=>"json"}
Run Code Online (Sandbox Code Playgroud)

这些模型都在

app/models/manager.rb
app/models/user.rb
Run Code Online (Sandbox Code Playgroud)

当我想现在访问控制器Manager内的模型api/v1/app/controller/manager/user.rbapi/v1/app/controller/manager.rb例如

class Api::V1::ManagerController < ApplicationController
  def index 
     Manager.find(...)
  end
end

class Api::V1::Manager::UserController < ApplicationController
  def index 
     Manager.find(...)
  end
end
Run Code Online (Sandbox Code Playgroud)

我得到这些错误

{"error":"uninitialized constant Api::V1::Manager::UserController::Manager"}%   
{"error":"uninitialized constant Api::V1::Manager::Manager"}%                                                                                 
Run Code Online (Sandbox Code Playgroud)

调用由正确的控制器处理:

Processing by Api::V1::Manager::UserController#index as JSON
Run Code Online (Sandbox Code Playgroud)

解决方案是在调用时使用双冒号前缀

`::Manager.find(...)`.
Run Code Online (Sandbox Code Playgroud)

我可以使用所有其他型号Admin.find(...)Controller.first正常使用.只有Manager.find(..)不起作用.

重命名命名空间ManagerResource仍会产生相同的错误消息.

我希望能够在不同的命名空间下对控制器进行分组,并且仍然能够以相同的方式访问所有模型吗?

更新

创建

api/v1/app/controller/api/v1/foo/customer_controller.rb
api/v1/app/controller/api/v1/manager_customer_controller.rb
Run Code Online (Sandbox Code Playgroud)

启动服务器(webrick)后,所有端点都正常工作.添加 Manager.first- 到任何控制器 - 或更改使用的文件中的某些内容会Manager...返回这些错误

`uninitialized constant Api::V1::Foo::UserController::Manager` 
`uninitialized constant Api::V1::ManagerUserController::Manager`
`uninitialized constant Api::V1::*any_controller*::Manager`
Run Code Online (Sandbox Code Playgroud)

重新启动服务器可以解决此问题.

我可以使用Controller.first或任何其他模型,例如api/v1/app/controller/controller.rb.服务器响应良好.

就像@Andrey Deineko指出的那样我现在理解模块和类名应该有所不同.

我不明白为什么这些错误只发生在特定模型上,当我在一个名称不同于模型的命名空间下减去控制器时?

更新II

我删除了所有经理相关的命名空间和控制器.所以我回到了原来的预控制器优化状态.

仅对Manger模型发生此错误.在Manager.class任何情况下在控制台显示Class.但在控制器中会发生这种情况:

module Api
 module V1
  class Manager < Api::ApiBaseController
   def index
     puts User.class #=> class
     puts Manager.class #=> module 
     puts ::Manager.class #=> class
     puts Controller.class #=> class
     ...
   end
  end
 end
end


class Api::V1::Manager < Api::ApiBaseController
   def index
     puts User.class #=> class
     puts Manager.class #=> {"error":"uninitialized constant Api::V1::ManagerController::Manager"}
     puts ::Manager.class  
     puts Controller.class  
     ...
   end
 end
Run Code Online (Sandbox Code Playgroud)

当我改变顺序时,::Manager首先一切都按预期工作,然后类匹配

 class Api::V1::Manager < Api::ApiBaseController
   def index
     puts User.class #=> class
     ::puts Manager.class #=> class
     puts Manager.class  #=> class
     puts Controller.class  #=> class
     ...
   end
 end
Run Code Online (Sandbox Code Playgroud)

命名空间Api::V1::...适用于所有其他控制器.

And*_*eko 1

原因很简单,答案就在于Ruby的常量解析机制。

基本上,模块和类同名是非常糟糕的主意。

但是,如果您确实需要模块和类具有相同的名称,请务必正确引用它们。

这意味着,如果您不想更改命名,Manager则引用类::您唯一的解决方案。

Rails 在开发和生产模式下为自动/预加载类添加了一些魔力,因此您可能会在不同模式下面临不同的问题。

您可能需要阅读有关在 Rails 中加载常量的官方指南。