简体   繁体   English

Rails:包含模块,但维护模块名称?

[英]Rails: Include module, but maintain module name?

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.现在,我想将其包含在我的申请 controller 中。

ApplicationController < ActionController::Base
  include Auth
end

This makes the sign_in method available in all my controllers.这使得sign_in方法在我的所有控制器中都可用。 Now, to make it clear that this is not a controller action, I would like to maintain the name, so my controllers read现在,为了明确这不是 controller 操作,我想保留名称,所以我的控制器读取

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.这显然是行不通的,因为 Rails 会在 Auth 模块中寻找 class 方法。 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?所以问题是......是否可以将一个模块包含到 controller 中,保留它的名称或名称空间,但仍然可以访问与 controller 相同的 scope? (in this case, the session variable). (在本例中为 session 变量)。

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:到目前为止,我想出的最不坏的方法是停止在 ApplicationController 中包含模块,而是在调用这样的 auth 方法时传递应用程序 controller 实例:

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

Calling this method from a controller using using self as an argument works.使用self作为参数从 controller 调用此方法有效。

Try this out?试试这个?

Uses an actual class for all the functionality and the controller has an instance of that class available;使用实际的 class 来实现所有功能,controller 有一个可用的 class 实例; 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基本上与上面的代码完全相同 - 请参阅current_user但您只需要一次传递 controller 实例,而不是在每次方法调用时传递

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    

It has been 9 years since I asked this question.我问这个问题已经 9 年了。 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.常量有自己的self ,当引用常量时,您会期望任何方法都是 class 方法。 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.除非在方法调用期间显式传递引用,否则您不会期望它们能够访问调用 object,在这种情况下,您具有双向依赖性,这会带来一系列问题。 That would be a code smell and should be a cause for refactoring the software design.那将是一种代码味道,应该成为重构软件设计的原因。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM