A copy of xxx has been removed from the module tree but is still active
Asked Answered
P

6

161

I'm pretty sure the error has nothing to do with the actual content of the TenantIdLoader module. Instead, it has something to do with ActiveSupport Dependencies.

I can't seem to get past this error. From what I've read, it's because either ActiveRecord::Base is getting reloaded or Company::TenantIdLoader is getting reloaded, and it's somehow not communicating that. Help, please! I'd really like to be able to get upgraded to Rails 4.2.

EDIT

I've now learned that it's because I'm referencing Tenant which is getting reloaded automatically. I need to be able to actually reference the class though, so does anyone know how to get around this?

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
Poriferous answered 14/4, 2015 at 19:59 Comment(9)
Does this answer help at all? #17562197Mange
Are you sure the Tenant class is involved? If you stub out the bits of that code that use Tenant do you still get an error?Homolographic
@WaynnLue yeah I think that's the reason, I just don't know how to fix it.Poriferous
@FrederickCheung I've got another file similar to this one that is erroring in the same way, and it always errors on the line related to Tenant, so it'd my best guess.Poriferous
Why guess when you could be sure by just hardcoding default_url_options ?Homolographic
@FrederickCheung after further testing, yes it definitely has to do with Tenant.Poriferous
Which is the line that throws the error?Homolographic
I've edited to show the simpler module. It errors on the self.tenant_id = line.Poriferous
Although you are not using Wisper in Rails here, it may be useful to other people to note that Wisper causes this problem fairly consistently if you do not follow the advice in this thread: #28347109Pall
H
221

Tenant is sort of a red herring - the error would occur if you referenced any bit of app that needs to be loaded by rails' const_missing trick.

The problem is that you are taking something reloadable (your module) and then including it in something not reloadable (ActiveRecord::Base or, in your earlier example ActionMailer::Base). At some point your code is reloaded and now ActiveRecord still has this module included in it even though rails thinks it has unloaded it. The error occurs when you reference Tenant because that causes rails to run its const_missing hooks to find out where Tenant should be loaded from and that code freaks out because the module where the constant search is starting from shouldn't be there.

There are 3 possible solutions:

  1. Stop including your module into non reloadable classes - either include into individual models, controllers as needed or create an abstract base class and include the module in there.

  2. Make this module non reloadable by storing it somewhere that isn't in autoload_paths (you'll have to require it explicitly since rails will no longer load it magically for you)

  3. Changing Tenant to ::Tenant (Object.const_missing will then be invoked, not Tenant.const_missing)

Homolographic answered 17/4, 2015 at 22:5 Comment(9)
I seem to have found a third solution, though I was wondering if you know why it works. If I reference it was ::Tenant, everything works out magically. Possibly because it's then loading it as a top-level constant? Maybe?Poriferous
then it's Object.const_missing that will be invoked not YourModule.const_missing so things should work outHomolographic
Backing out to top-level using :: worked for me, too!Smalley
I had this issue occurring from time to time and in my case it was related to spring, so doing ./bin/spring stop was resolving it.Swansea
instead of including in AR::Base i just include everything into ApplicationRecord since Rails5 hast that included. great idea ;)Pillow
The Rails is not getting the 'Tenant' constant. So mention the Full scope of the Tenant name to make it work. It has some namespace issue I guessDerrick
Adding my variation on this issue — it can be difficult to figure out what the "offending" class/module actually is. In my case, it was a Rails model being referenced in a class that was in a subfolder of an autoload path (and thus didn't seem to count as autoloading). Prefixing the model with :: fixed it.Cytoplasm
I LOVE that this is a runtime Ruby/Rails error - unlike any other language, dynamic or not, Ruby gives developers the true unlimited flexibility to have literally no idea where modules are defined until your program executes (and in what order it executes). It's so well designed.Sophistry
@FrederickCheung I want to try creating an abstract base class and including modules there. Can you point to any resources on how to do that?Hbomb
A
52

Changing ModuleName to ::ModuleName worked for me.

Ar answered 8/2, 2017 at 20:10 Comment(0)
P
7

Not sure if this will help anyone, but I had this suddenly start happening after a change that seemed unrelated. It went away after I restarted the application server.

Pinsk answered 14/8, 2018 at 8:17 Comment(0)
M
0

Changing ModuleName to 'ModuleName'.constantize solved the issue for me.

Mullock answered 10/9, 2019 at 10:9 Comment(0)
D
0

Another way to solve this issue is to require the module directly in the file that is not reloadable.

At the top of lib/company/tenant_id_loader.rb put require_relative '../../app/models/tenant' or whatever the path is relative to the id loader to the tenant model.

Disrate answered 8/10, 2020 at 16:55 Comment(0)
R
-5

What worked for me:

Update config.eager_load = false to true

in config/environments/development.rb

Ruby 2.6.5
Rails 5.1.6

Rives answered 1/3, 2020 at 2:38 Comment(1)
Yeah definitely don't do this. That's going to kill your ability to reload code in development.Poriferous

© 2022 - 2024 — McMap. All rights reserved.