在纯红宝石中:
class A
TEST = "foo"
end
puts A::TEST
# foo
class A
TEST = "bar"
end
# (irb): warning: already initialized constant TEST
puts A::TEST
# bar
在 Ruby 中,您可以随时打开一个类并重新声明其中的任何内容。它只对常量发出警告,但它确实会继续进行更改。
让我们甚至更简洁地重写该代码:
class A
TEST = "foo"
TEST = "bar"
end
# (irb):3: warning: already initialized constant TEST
即使您没有真正更改常量,而只是将其设置为相同的值,也会出现警告。
class A
TEST = "foo"
TEST = "foo"
end
# (irb):3: warning: already initialized constant TEST
所以总的来说,它只是一个可以安全忽略的警告。
在 Rails 中:
在开发期间,Rails 会重新加载应用程序中任何更改的代码。较新版本的 Rails 在确定哪些文件实际发生了更改方面也非常聪明,然后只重新加载那些文件。所以假设你有这个控制器:
class TestController < ApplicationController
FOO = "bar"
def index
...
end
end
如果您在其中进行任何更改,该文件将被重新加载。当文件重新加载时,FOO = "bar"
再次解析,你最终会得到同样的警告。
解决方案:
如果您使用的是 Rails 3.0 或 3.1,请尝试使用active_reload gem 并查看您的警告是否消失(它可能会在重新加载之前卸载您的类,这可能会导致警告消失)
使用以下定义常量:
FOO = "bar" unless const_defined?(:FOO)
只有当它不存在时,这才会定义常量。所以你会避免警告。
使用辅助方法来定义常量并自动执行此操作
module ConstDefiner
def define_constant(name, value)
const_set(name, value) unless const_defined?(name)
end
end
ActionController::Base.send :extend, ConstDefiner
ActiveRecord::Base.send :extend, ConstDefiner
# Now in all your controllers/models:
# instead of FOO = "value" unless const_defined?(:FOO), use:
define_constant :FOO, "value"
这些警告仅在开发模式下发生。您将不需要所有的unless const_defined?(:FOO)
生产。通常不建议在生产中使用特定于开发的代码(除非它真的很重要)
请记住,当您说 时FOO = "bar" unless const_defined?(:FOO)
,即使您真的对FOO
常量进行了更改,它也不会在定义后重新加载。您必须停止并启动 rails 服务器才能重新加载它。但是与实际代码相比,在开发过程中修改常量的概率有点低,而且不是很频繁。如前所述,这不会以任何方式影响生产代码。
编辑:添加到 active_reload gem 的链接