Rails'忘记了初始化程序和查询之间的类

时间:2018-04-24 10:47:23

标签: ruby-on-rails ruby autoload

我在Rails上遇到了一个奇怪的问题。

我们已经设置了一个Hook类来处理我们应用程序中的小型pub / sub机制,它就像这样

class Hook
  @subscriptions = {}

  class << self
    def subscribe(message, &block)
      @subscriptions[message] ||= []
      @subscriptions[message] << block
    end

    def publish(message)
      @subscriptions[message].each(&:call)
    end
  end
end

(它更加充实,但你明白了。)

问题是:

在初始值设定项中,我们得到了Hook.subscribe(:change) { ... } 但是当模型调用Hook.publish(:change)时,没有任何反应。快速检查表明,在模型再次调用Hook之前,defined? Hook会返回nil

模型中的代码是

after_commit do
  # byebug
  Hook.publish(:change)
end

甚至更奇怪:在初始化器中我设置了一个全局变量来保存常量$hook = Hook,常量确实位于模型中的$hook变量内但与自动加载的Hook不匹配

# inside a debugger in the model

> defined? Hook
=> nil

> $hook
=> Hook

> Hook # will trigger autoloading
=> Hook

> defined? Hook
=> "constant"

> Hook == $hook
=> false

> Hook.instance_variable_get(:@subscriptions)
=> {}

> $hook.instance_variable_get(:@subscriptions)
=> { change: [<Proc:...>] }

> Hook.object_id == $hook.object_id
=> false

如果我通过调试器将其设置为常量Hook = $hook,则所有内容都会再次正常运行 - 即使在请求中使用适当的变量也可以保持常量。

我已经到了最后。任何人都知道可能会发生什么?

1 个答案:

答案 0 :(得分:2)

我终于找到了一个解决方案,即使我不完全理解它(我仍然有点不清楚Rails如何处理自动加载我猜 - 当我有时我还需要深入调查时间)。

Hook类位于一个模块(OurApp::Hook)中,为了清楚起见,我已经省略了这个模块(显然我的错误)。 我注意到OurApp.constants丢失了Hook以外的一些常量。 我进去了lib/our_app.rb并对其进行了修改:

module OurApp
  autoload :Hook, 'lib/our_app/hook.rb'
  # ...
end

这似乎可以解决问题,而不是更多问题。

谢谢大家!