redasus redasus - 5 months ago 30
Ruby Question

Devise sign_in resource works even without importing module

So, I was customizing devise in a custom sign up page which required me to sign_in a user after creating the account along with some other operations. After creating the resource I did

sign_in resource if resource.active_for_authentication?


and it signs in the user. My controller inherits the
ApplicationController
and I haven't included any modules like this

include Devise::Controllers::SignInOut


How did rails know about the

sign_in


method

Answer

Basic answer - the module Devise::Controllers::Helpers (which includes Devise::Controllers::SignInOut that you discovered) is automatically included in ApplicationController.

Going deeper

Devise is a Rails Engine - you can check this article for brief review.

Engines can be considered miniature applications that provide functionality to their host applications. A Rails application is actually just a "supercharged" engine, with the Rails::Application class inheriting a lot of its behavior from Rails::Engine.

...

Engines are also closely related to plugins.

Then, you fill find following string at rails.rb of Devise engine (rails.rb is convention class name for Rails engine) here:

   initializer "devise.url_helpers" do
      Devise.include_helpers(Devise::Controllers)
    end

And if you look at this include_helpers call, this it what id does:

 def self.include_helpers(scope)
    ActiveSupport.on_load(:action_controller) do
      include scope::Helpers if defined?(scope::Helpers)
      include scope::UrlHelpers
    end

    ActiveSupport.on_load(:action_view) do
      include scope::UrlHelpers
    end
  end

ActiveSupport on_load call is a Rails feature to lazy_load components. source:

# lazy_load_hooks allows Rails to lazily load a lot of components and thus # making the app boot faster.

In this case, those include commands for controller will be executed when controller is loaded, but not on server start. Check this or any other articles on the concept.

And this is the place where that lazy block is run - source:

module ActionController
  # Action Controllers are the core of a web request in \Rails. They are made up of one or more actions that are executed
  # on request and then either it renders a template or redirects to another action. An action is defined as a public method
  # on the controller, which will automatically be made accessible to the web-server through \Rails Routes.
  #
  # By default, only the ApplicationController in a \Rails application inherits from <tt>ActionController::Base</tt>. All other
  # controllers in turn inherit from ApplicationController. This gives you one class to configure things such as
  # request forgery protection and filtering of sensitive request parameters.
 ...
  class Base < Metal
    ...
    ActiveSupport.run_load_hooks(:action_controller, self)
  end
end

BTW, your ApplicationController generated by Rails is inherited from ActionController::Base