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

我很确定这个错误与 TenantIdLoader模块的实际内容没有任何关系。相反,它与 ActiveSupport依赖关系有关。

我似乎无法克服这个错误。据我所知,这是因为要么 ActiveRecord::Base被重新加载,要么 Company::TenantIdLoader被重新加载,而且它不知何故没有传达这一点。救命啊!我真的很希望能够升级到 Rails 4.2。

剪辑

我现在知道这是因为我引用了 Tenant,它会自动重新加载。我需要能够真正引用这个类,所以有人知道如何解决这个问题吗?

Config/application.rb

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

Config/initializer/company.rb

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

Lib/company/rent _ 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
70549 次浏览

Tenant是一种转移注意力的方法——如果你引用了任何一个需要使用 Rails 的 const_missing技巧来加载的应用程序,那么错误就会发生。

问题是,您正在获取一些可重新加载的内容(您的模块) ,然后将其包含在一些不可重新加载的内容中(ActiveRecord::Base或者,在您早期的示例 ActionMailer::Base中)。在某个时候,代码被重新加载,现在 ActiveRecord 仍然包含这个模块,即使 Rails 认为它已经卸载了它。当你引用 Tenant 的时候,错误就会发生,因为这会导致 Rail 运行它的 const_missing钩子来找出 Tenant 应该从哪里加载,而且这段代码会崩溃,因为常量搜索从哪里开始的模块不应该在那里。

有三种可能的解决办法:

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

  2. 通过将该模块存储在 autoload _ path 之外的地方,使其不可重载(您必须显式地要求它,因为 Rails 将不再神奇地为您加载该模块)

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

模块名称改成 翻译: ModuleName对我来说很管用。

不知道这是否能帮到任何人,但是我突然发现这个在一个看起来毫不相关的变化之后发生了。在我重新启动应用服务器之后它就消失了。

ModuleName改成 'ModuleName'.constantize为我解决了这个问题。

对我有效的方法是:

更新 config.eager_load = falsetrue

config/environments/development.rb

Ruby 2.6.5
Rails 5.1.6

解决这个问题的另一种方法是直接要求不可重载的文件中的模块。

lib/company/tenant_id_loader.rb的顶部放置 require_relative '../../app/models/tenant'或任何与租户模型的 id 加载程序相关的路径。