模块树中的xxx副本已被移除,但仍然处于活动状态。

161

我相信错误与TenantIdLoader模块的实际内容无关。 相反,它与ActiveSupport Dependencies有关。

我似乎无法解决这个错误。 根据我所了解的,这是因为要么重新加载了ActiveRecord :: Base,要么重新加载了Company :: TenantIdLoader,而且它在某种程度上没有得到通信。 求助!我真的很想升级到Rails 4.2。

编辑

我现在知道这是因为我正在引用自动重新加载的Tenant。但我仍然需要能够实际引用该类,那么有谁知道如何解决这个问题吗?

config/application.rb

config.autoload_paths += %W( #{config.root}/lib/company )

config/initializers/company.rb

ActionMailer::Base.send(:include, Company::TenantIdLoader)

lib/company/tenant_id_loader.rb

module Company
  module TenantIdLoader

    extend ActiveSupport::Concern

    included do
      cattr_accessor :tenant_dependency
      self.tenant_dependency = {}
  
      after_initialize do
        self.tenant_id = Tenant.active.id if self.class.tenant_dependent? and self.new_record? and Tenant.active.present? and !Tenant.active.zero?
      end
    end

    # class methods to be mixed in
    module ClassMethods
  
      # returns true if this model's table has a tenant_id
      def tenant_dependent?
        self.tenant_dependency[self.table_name] ||= self.column_names.include?('tenant_id')
      end
  
    end

  end
end

4
这个答案对你有帮助吗?https://dev59.com/COo6XIcBkEYKwwoYNBdQ#23008837 - Waynn Lue
@WaynnLue 是的,我认为那就是原因,只是我不知道该如何修复它。 - kddeisz
@FrederickCheung 我有另一个与此文件类似的文件,在相同的方式出现错误,而且它总是在涉及Tenant的那一行出错,所以这是我最好的猜测。 - kddeisz
@FrederickCheung 经过进一步的测试,是的,它确实与租户有关。 - kddeisz
1
虽然在这里你没有在Rails中使用Wisper,但是对于其他人来说,注意到如果你不遵循这个线程中的建议,Wisper会相当一致地引起这个问题可能会很有用:https://dev59.com/uYfca4cB1Zd3GeqPkpSM#28362286 - Steve N
显示剩余4条评论
6个回答

221

Tenant 是一个误导性的术语 - 如果您引用了任何需要通过 Rails 的 const_missing 技巧加载的应用程序部分,就会出现错误。

问题在于,您正在将可重载的东西(您的模块)包含在不可重载的东西中(ActiveRecord::Base,或者在您之前的示例中是 ActionMailer::Base)。在某个时候重新加载您的代码,这时 ActiveRecord 仍然将该模块包含在其中,尽管 rails 认为已将其卸载。当您引用 Tenant 时,错误就会发生,因为这会导致 rails 运行其 const_missing 钩子程序以查找应从何处加载 Tenant,并且该代码在搜索常量的模块中启动,而该模块不应在其中。

有三种可能的解决方案:

  1. 停止将您的模块包含到不可重载的类中 - 要么根据需要将其包含到各个模型、控制器中,要么创建一个抽象基类并在其中包含该模块。

  2. 使此模块不可重载,通过将其存储在 autoload_paths 之外的地方(您必须显式进行 require,因为 rails 不再为您自动加载它)

  3. 将 Tenant 更改为 ::Tenant(这样将调用 Object.const_missing,而不是 Tenant.const_missing


40
我好像找到了第三个解决方案,但我想知道你是否知道它为什么有效。如果我引用 "::Tenant",一切都会神奇地解决。可能是因为它被加载为顶级常量吧?也许? - kddeisz
3
那么会调用Object.const_missing而不是YourModule.const_missing,所以事情会顺利进行。 - Frederick Cheung
7
使用 :: 返回到顶层对我也起作用了! - Alex Moore-Niemi
13
我偶尔会遇到这个问题,在我的情况下与Spring有关,因此运行./bin/spring stop可以解决它。 - santuxus
7
我很喜欢这是一个“运行时”Ruby/Rails错误 - 不像其他任何语言,无论是动态的还是静态的,Ruby给开发者真正无限的灵活性,让他们在程序执行(以及执行顺序)之前几乎不知道模块定义在哪里。它设计得非常好。 - Andy Ray
显示剩余4条评论

52

ModuleName 改为 ::ModuleName 对我有用。


7

不确定这是否对任何人有帮助,但我在一个看似无关的更改后突然遇到了这个问题。重启应用服务器后问题消失了。


0

ModuleName更改为'ModuleName'.constantize解决了我的问题。


0
另一种解决此问题的方法是直接在不可重新加载的文件中要求该模块。
lib/company/tenant_id_loader.rb的顶部放置require_relative '../../app/models/tenant',或者根据租户模型相对于id加载程序的路径进行调整。

-5

对我有效的方法:

config.eager_load = false更新为true

config/environments/development.rb中进行修改

Ruby 2.6.5
Rails 5.1.6


5
一定不要这样做。那会破坏你在开发中重新加载代码的能力。 - kddeisz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接