Ruby 模块中常量的范围
我在 mixin 模块中的恒定范围方面遇到了一些问题。假设我有这样的
module Auth
USER_KEY = "user" unless defined? USER_KEY
def authorize
user_id = session[USER_KEY]
def
end
USER_KEY 常量应默认为“user”,除非它已经定义。现在我可能会将其混合到几个地方,但在其中一个地方 USER_KEY 需要不同,所以我们可能有这样的东西
class ApplicationController < ActionController::Base
USER_KEY = "my_user"
include Auth
def test_auth
authorize
end
end
我希望 USER_KEY 在授权中使用时将是“my_user”,因为它已经定义了,但它仍然是“用户”,取自 USER_KEY 的模块定义。有人知道如何获得使用 USER_KEY 类版本的授权吗?
I'm having a little problem with constant scope in mixin modules. Let's say I have something like this
module Auth
USER_KEY = "user" unless defined? USER_KEY
def authorize
user_id = session[USER_KEY]
def
end
The USER_KEY constant should default to "user" unless it's already defined. Now I might mix this into a couple of places, but in one of those places the USER_KEY needs to be different, so we might have something like this
class ApplicationController < ActionController::Base
USER_KEY = "my_user"
include Auth
def test_auth
authorize
end
end
I would expect that USER_KEY would be "my_user" when used in authorize, since it's already defined, but it's still "user", taken from the modules definition of USER_KEY. Anyone have any idea how to get authorize to use the classes version of USER_KEY?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您在
Auth
中声明(甚至有条件)的USER_KEY
在全球范围内称为Auth::USER_KEY
。它不会“混合”到包含模块中,尽管包含模块可以以非完全限定的方式引用密钥。如果您希望每个包含模块(例如
ApplicationController
)能够定义自己的USER_KEY
,请尝试以下操作:不过,如果您要遇到所有这些麻烦,您不妨将其设为类方法:
或类级访问器:
The
USER_KEY
you declared (even conditionally) inAuth
is globally known asAuth::USER_KEY
. It doesn't get "mixed in" to including modules, though including modules can reference the key in a non-fully-qualified fashion.If you want each including module (e.g.
ApplicationController
) to be able to define its ownUSER_KEY
, try this:If you're going to go to all this trouble, though, you might as well just make it a class method:
or a class-level accessor:
Ruby 中的常量没有全局作用域。常量在任何范围内都是可见的,但您必须指定在哪里可以找到该常量。当你开始一个新的类、模块或 def 时,你就开始了一个新的作用域,如果你想要另一个作用域中的常量,你必须指定在哪里找到它。
Constants don't have global scope in Ruby. Constants can be visible from any scope, but you must specify where the constant is to be found. When you begin a new class, module, or def, you begin a new scope, and if you want a constant from another scope, you have to specify where to find it.
这是一个简单的解决方案。
更改:
USER_KEY
是否存在。。
解释
您所看到的行为并非特定于 Rails,而是由于如果未通过
::
显式限定作用域,则 ruby 会查找常量(我称之为“默认”上面)。使用“当前执行代码的词法范围”查找常量。这意味着 ruby 首先在执行代码的模块(或类)中查找常量,然后向外移动到每个连续的封闭模块(或类),直到找到在该范围内定义的常量。在您的控制器中,您调用
authorize
。但是当authorize
执行时,当前执行的代码是在Auth
中。这就是查找常量的地方。如果 Auth 没有 USER_KEY,但封闭模块有,则将使用封闭模块。示例:这种情况的一个特殊情况是顶级执行环境,它被视为属于类
Object
。一个陷阱是使用作用域运算符 (
::
) 定义模块或类:请注意,常量的定义可能晚于方法的定义。查找仅在访问 USER_KEY 时发生,因此这也有效:
Here's a simple solution.
Changes:
USER_KEY
..
Explanation
The behavior you're seeing isn't specific to rails, but is due to where ruby looks for constants if not explicitly scoped via
::
(what I call the "default" above). Constants are looked up using the "lexical scope of the currently executing code". This means that ruby first looks for the constant in the executing code's module (or class), then moves outward to each successive enclosing module (or class) until it finds the constant defined on that scope.In your controller, you call
authorize
. But whenauthorize
is executing, the currently executing code is inAuth
. So that is where constants are looked up. If Auth didn't haveUSER_KEY
, but an enclosing module has it, then the enclosing one would be used. Example:A special case of this is the top-level execution environment, which is treated as belonging to class
Object
.One pitfall is defining a module or class with the scoping operator (
::
):Note that the constant can be defined much later than the method is defined. The lookup only happens when USER_KEY is accessed, so this works too:
如果您的项目在 Rails 中,或者至少使用 ActiveSupport 模块,您可以显着减少必要的逻辑糖:
我很惊讶没有人建议这种方法,因为看到 OP 的场景如何驻留在一个轨道应用程序...
If your project is in Rails, or at least utilizes the
ActiveSupport
module, you can significantly reduce the necessary logic sugar:I'm surprised no one suggested this approach, seeing as how the OP's scenario resided within a Rails app...
对于OP的问题,有一个比这里揭示的其他答案简单得多的解决方案:
@james-a-rosen的答案给了我尝试这个的灵感。我不想走他的路,因为我有几个常量在多个类之间共享,每个常量都有不同的值,而且他的方法看起来需要大量输入。
There's a far simpler solution to the OP's question than the other answers here reveal:
It was @james-a-rosen's answer that gave me the inspiration to try this. I didn't want to go his route because I had several constants that are shared among several classes, each with a different value, and his method looked like a lot of typing.