xxx的副本已从模块树中删除,但仍处于活动状态


129

我很确定该错误与TenantIdLoader模块的实际内容无关。相反,它与ActiveSupport依赖关系有关。

我似乎无法摆脱这个错误。从我读到的内容来看,这是因为要么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

3
这个答案有帮助吗?stackoverflow.com/questions/17561697/...
— Waynn略

您确定涉及租户类吗?如果将使用Tenant的代码中的位存根,仍然会出错?
— Frederick Cheung

@WaynnLue是的,我认为这就是原因,我只是不知道如何解决。
— kddeisz 2015年

@FrederickCheung我有另一个与此文件类似的文件,该文件以相同的方式出错,并且总是在与Tenant相关的行上出错,所以这是我的最佳猜测。
— kddeisz 2015年

1
虽然你没有使用WISPER在Rails的这里,它可能是其他人有用的注意,WISPER导致此问题非常一致,如果你不按照这个线程的建议:stackoverflow.com/questions/28346609/...
— 史蒂夫ñ

Answers:


182

Tenant有点像红色鲱鱼-如果您引用需要通过Rails的const_missing技巧加载的应用程序的任何部分,则会发生错误。

问题是您正在获取可重装的东西(您的模块),然后将其包含在不可重装的东西中(ActiveRecord::Base或者,在您先前的示例中ActionMailer::Base)。在某个时候,您的代码被重新加载,并且即使Rails认为ActiveRecord已卸载它,现在ActiveRecord仍然包含该模块。当您引用Tenant时会发生错误,因为这会导致Rails运行其const_missing钩子来找出应该从哪个位置加载Tenant,并且该代码会出现异常,因为不应该从那里开始进行常量搜索。

有3种可能的解决方案:

  1. 停止将模块包含在不可重载的类中-可以根据需要将模块包含在单个模型中,也可以将其包含在控制器中,或者创建一个抽象基类并将模块包含在其中。

  2. 通过将模块存储在autoload_paths之外的某个地方,使其不可重载(您必须明确要求它,因为Rails将不再为您神奇地加载它)

  3. 将Tenant更改为:: Tenant(Object.const_missing然后将调用,而不是Tenant.const_missing)


30
我似乎已经找到了第三个解决方案,尽管我想知道您是否知道它为什么有效。如果我引用的是:: Tenant,那么一切都会神奇地完成。可能是因为它随后将其作为顶级常量加载?也许?
— kddeisz 2015年

3
那么将调用Object.const_missing而不是YourModule.const_missing,这样事情应该可以解决
— Frederick Cheung

6
回到顶层使用::对我也有用!
— Alex Moore-Niemi 2015年

7
我时有发生此问题,在我的情况下,它与春天有关,因此可以./bin/spring stop解决此问题。
— santuxus

1
我喜欢这是一个运行时 Ruby / Rails错误-与其他任何语言(无论是否动态)不同,Ruby为开发人员提供了真正的无限灵活性,使您几乎不知道在程序执行之前(在执行顺序上)定义模块的位置。如此精心设计。
— 安迪·雷


6

不知道这是否会对任何人有帮助,但是在发生似乎无关的更改之后,我突然开始发生这种情况。重新启动应用程序服务器后,它消失了。


0

更改ModuleName以'ModuleName'.constantize解决这个问题对我来说。


0

对我有用的是:

更新config.eager_load = false到true

在 config/environments/development.rb

Ruby 2.6.5
Rails 5.1.6


1
是的,绝对不要这样做。那将杀死您在开发中重新加载代码的能力。
— kddeisz

-13

有时候你只是

重新启动服务器,


我不明白为什么要拒​​绝这个答案?重复意味着很重要!为什么简单的事情有很多废话?
— Albert.Qing

7
这是不好的意思,因为(a)无论您重新启动服务器多少次,它都不能解决原始问题中的问题,并且(b)您不应该简单地处理问题的症状,而要处理问题本身。
— tjbp

@tjbp plz注意单词“有时”好吗?
— Albert.Qing

问题是,如果每次更改后都必须重新启动服务器,则无法在开发模式下调试应用程序。
— Max Ivak '18

2
我将对此答案投赞成票,因为如果您使用的是Mongoid并从Rails控制台删除对象X,则会出现此错误:A copy of X has been removed from the module tree but is still active在所有具有Object的页面上Y.embeds X,重新启动服务器确实适用于此特定情况。但是您应该编辑答案。
— 卢卡斯·安德拉德
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.