I refactored my rails app in a way that for every sub resources i create a controller is the according namespace.
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
The class definition of the user resource under the manager namespace looks like this
class Api::V1::Manager::UserController < ApplicationController
This controller is reachable through routes.rb:
 resources :manager , only: [:show ] do
   resources :user, only: [:index], controller: 'manager/user'
 end
which generates
/api/v1/manager/:manager_id/user(.:format)       api/v1/manager/manager#index {:format=>"json"}
The models are all under
app/models/manager.rb
app/models/user.rb
When i want to access now the Manager model inside the api/v1/app/controller/manager/user.rb controller or  in api/v1/app/controller/manager.rb e.g
class Api::V1::ManagerController < ApplicationController
  def index 
     Manager.find(...)
  end
end
class Api::V1::Manager::UserController < ApplicationController
  def index 
     Manager.find(...)
  end
end
i get these errors
{"error":"uninitialized constant Api::V1::Manager::UserController::Manager"}%   
{"error":"uninitialized constant Api::V1::Manager::Manager"}%                                                                                 
The calls are handled by the correct controllers :
Processing by Api::V1::Manager::UserController#index as JSON
The solution is to use the double colon prefix with the call
`::Manager.find(...)`.
I can use all other models Admin.find(...) or Controller.first normally. Only the Manager.find(..) is not working.
Renaming the namespace to ManagerResource still produces the same error message.
I would like to be able to group controllers under different namespaces and still access all the models the same way how is that possible?
Update
Created
api/v1/app/controller/api/v1/foo/customer_controller.rb
api/v1/app/controller/api/v1/manager_customer_controller.rb
After starting the server (webrick) all endpoints are working.
Adding  Manager.first - to any controller- or changing something in a file which uses Manager... returns these errors
`uninitialized constant Api::V1::Foo::UserController::Manager` 
`uninitialized constant Api::V1::ManagerUserController::Manager`
`uninitialized constant Api::V1::*any_controller*::Manager`
Restarting the server solves this issue.
I am able to use Controller.first or any other model in e.g. api/v1/app/controller/controller.rb.The the server responds well.
Like @Andrey Deineko pointed out i understand now the module and class names should differ.
What i dont understand is why these errors occur only for a specific model when i substract controllers under a namespace which with a different name than the models?
Update II
I removed all manager related namespaces and controllers. So i am back to the original pre-controller-optimization state.
This error occurs only for the Manger model. In the console Manager.class shows in any case Class.
But in the controller this happens:
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
when i change the order so that ::Manager is first everything works as expected and also the classes then match
 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
The namespace Api::V1::... works for every other controller.
The reason is simple and the answer lies in Ruby's constants resolution mechanism.
Basically it is super bad idea to have a module and class with the same name.
But if you definitely need to have same name for both module and class, be sure to correctly reference each of them.
Meaning, that referencing Manager class with :: is your only solution if you don't want to change the naming.
Rails add some magic to auto/preloading classes in development and production mode, so you could face different issues in different modes.
You may want to read through this official guide on loading constants in Rails.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With