Rails初始化器与查询间Hook类丢失问题求助
解决Rails中Hook类订阅在代码重新加载后丢失的问题
这个问题我太熟悉了!核心原因是Rails开发环境的自动代码重新加载机制——当你修改代码后,Rails会重新加载相关类,而你的Hook类被重新加载时,原来的@subscriptions类实例变量会被重置为空的{},但初始化器只会在服务器启动时运行一次,所以重新加载后之前的订阅就全没了。
下面给你两种靠谱的解决方案:
方案1:用config.to_prepare注册订阅(推荐)
Rails提供了config.to_prepare回调,它在服务器启动时执行一次,并且在开发环境每次代码重新加载后都会再次执行,完美适配你的场景。
修改你的初始化器代码,把订阅逻辑放到这个回调里:
# config/initializers/hook_setup.rb Rails.application.config.to_prepare do # 在这里注册所有Hook订阅 Hook.subscribe(:your_message) do # 你的订阅处理逻辑 end Hook.subscribe(:another_message) do # 另一个订阅逻辑 end end
这样不管Hook类被重新加载多少次,订阅都会被重新注册,不会丢失。
方案2:修改Hook类,使用常量存储订阅
如果你不想改动初始化器,也可以修改Hook类,把订阅存储到常量里(常量在类重新加载时不会被重置):
class Hook # 用常量存储订阅,避免重新加载时丢失 SUBSCRIPTIONS = {} class << self def subscribe(message, &block) SUBSCRIPTIONS[message] ||= [] SUBSCRIPTIONS[message] << block end def publish(message) # 用&.避免message不存在时的NilError SUBSCRIPTIONS[message]&.each(&:call) end end end
不过要注意:如果你的订阅block依赖其他会被重新加载的类,可能会出现“旧类实例”的问题(block里引用的是重新加载前的类),所以这种方法更适合简单的、不依赖其他动态类的订阅逻辑。
为什么原来的代码会失效?
再补充下原理:Rails开发环境中,config.cache_classes默认是false,意味着类会在修改后被重新加载。你的@subscriptions是Hook类的实例变量,当Hook被重新加载时,新的Hook类会重新初始化@subscriptions = {},而原来的初始化器已经执行过了,不会再重新注册订阅,所以就出现了“遗忘”的情况。
内容的提问来源于stack exchange,提问作者Jérémie Bonal
相关产品推荐
相关产品推荐

