Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails module scope

Given the following controller structure:

# application_controller.rb
class ApplicationController < ActiveController::Base; end

# pages_controller.rb
class PagesController < ApplicationController; end

# admin/application_controller.rb
module Admin
  class ApplicationController < ::ApplicationController; end
end

# admin/pages_controller.rb
module Admin
  class PagesController < ApplicationController; end
end

One would expect Admin::PagesController to inherit from Admin::ApplicationController and it does. But I have noticed that sometimes it inherits from ::ApplicationController.

So I decided not to risk it and changed declaration of all controllers in /admin to specifically target Admin::ApplicationController

# admin/pages_controller.rb
module Admin
  class PagesController < Admin::ApplicationController; end
end

Okay that works, but from what I know it was correct in the first place. Why Rails inherits from a wrong controller sometimes?

Admin::PagesController sometimes inherits from ApplicationController instead of Admin::ApplicationController despite both being in the same module Admin

like image 887
firedev Avatar asked Apr 15 '15 05:04

firedev


2 Answers

The problem here is rails' development mode code loading: in general code is loaded when you try to do something with a constant (eg subclass from it) and that constant doesn't exist. This results in const_missing being called and rails uses it this to try to load the class (for a detailed description see the guide).

If neither ApplicationController nor Admin::ApplicationController exist then when you access your admin pages controller ruby will hit that const_missing and try to load admin/application_controller.rb

However if ApplicationController is already loaded then ruby won't fire const_missing since it perfectly legal for a class in the admin module to inherit from something at the toplevel.

The solution as you say is to make explicit what you are inheriting from. Personally in my own apps I use Admin::BaseController as the base class.

like image 80
Frederick Cheung Avatar answered Nov 03 '22 06:11

Frederick Cheung


Another option is to use require_dependency to point Rails to the correct file:

# admin/application_controller.rb

require_dependency 'admin/application_controller'

module Admin
  class PagesController < ApplicationController
  end
end
like image 31
Stefan Avatar answered Nov 03 '22 08:11

Stefan