Domanda

Consider this code

module Auth

  def sign_in(user)
    #some stuff
    session[:user_id] = user.id
  end

end

Now, I want to include this in my application controller.

ApplicationController < ActionController::Base
  include Auth
end

This makes the sign_in method available in all my controllers. Now, to make it clear that this is not a controller action, I would like to maintain the name, so my controllers read

def sign_user_in
  # Some stuff
  Auth.sign_in(@user)
end

This obviously does not work, because Rails will look for the class method in the Auth module. So the question is... Is it possible to include a module into the controller, preserve it's name or namespace, but still get access to the same scope as the controller? (in this case, the session variable).

So far the least bad way I have come up with is stop including the module and in the ApplicationController and instead pass the application controller instance along when calling an auth method like this:

def current_user(controller)
  User.find(controller.session[:user_id])
end

Calling this method from a controller using using self as an argument works.

È stato utile?

Soluzione 2

It has been 9 years since I asked this question. In the meantime I have realized that it is not a good idea to do this as it rubs against the language.

Constants have their own self and when referencing a constant, you would expect any methods to be class methods. You would not expect them to have access to the calling object unless an a reference is explicitly passed during the method call, in which case you have a bidirectional dependency, which comes with its own set of problems. That would be a code smell and should be a cause for refactoring the software design.

Altri suggerimenti

Try this out?

Uses an actual class for all the functionality and the controller has an instance of that class available; basically the exact same code you have above - see current_user but you only need to pass the controller instance in once, not on every method call

module Auth
  # this method is 'mixed' into controller (self)
  def initialize_authorizer
    @authorizer = ::Auth::Authorizer(self)
  end

  # this class doesn't need to be in this namespace (module), put it where ever makes sense
  class Authorizer
    def initialize(controller)
      @controller = controller
    end

    attr_reader :controller

    def sign_in(user)
      #some stuff
      controller.session[:user_id] = user.id
    end

    def current_user
      User.find(controller.session[:user_id])
    end        
  end
end

ApplicationController < ActionController::Base
  include Auth

  before_filter :initialize_authorizer
end

def sign_user_in
  # Some stuff
  @authorizer.sign_in(@user)
end    
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top