Kopia xxx została usunięta z drzewa modułów, ale jest nadal aktywna

129

Jestem prawie pewien, że błąd nie ma nic wspólnego z rzeczywistą zawartością TenantIdLoadermodułu. Zamiast tego ma coś wspólnego z ActiveSupportzależnościami.

Wydaje się, że nie mogę obejść tego błędu. Z tego, co przeczytałem, wynika to z tego, że albo ActiveRecord::Basejest ponownie ładowany, albo Company::TenantIdLoaderjest ponownie ładowany, i jakoś tego nie przekazuje. Prosimy o pomoc! Naprawdę chciałbym mieć możliwość aktualizacji do Rails 4.2.

EDYTOWAĆ

Teraz dowiedziałem się, że dzieje się tak, ponieważ odwołuję się do tego, Tenantktóry jest automatycznie ładowany ponownie. Muszę jednak mieć możliwość odniesienia się do klasy, więc czy ktoś wie, jak to obejść?

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
kddeisz
źródło
3
Czy ta odpowiedź w ogóle pomaga? stackoverflow.com/questions/17561697/…
Waynn Lue
Czy na pewno w grę wchodzi klasa Tenant? Jeśli usuniesz bity tego kodu, które używają dzierżawy, czy nadal pojawia się błąd?
Frederick Cheung
@WaynnLue yeah Myślę, że to jest powód, po prostu nie wiem, jak to naprawić.
kddeisz
@FrederickCheung Mam inny plik podobny do tego, który zawiera błędy w ten sam sposób i zawsze zawiera błędy w linii związanej z Najemcą, więc zgadłem.
kddeisz
1
Chociaż nie używasz tutaj Wispera w Railsach, innym osobom może przydać się zauważenie, że Wisper powoduje ten problem dość konsekwentnie, jeśli nie zastosujesz się do porady w tym wątku: stackoverflow.com/questions/28346609/ ...
Steve N

Odpowiedzi:

182

Tenantto coś w rodzaju czerwonego śledzia - błąd wystąpiłby, gdybyś odwołał się do dowolnego fragmentu aplikacji, który musi zostać załadowany przez const_missingsztuczkę railsów.

Problem polega na tym, że bierzesz coś, co można przeładować (twój moduł), a następnie dołączasz to do czegoś, czego nie można przeładować ( ActiveRecord::Baselub we wcześniejszym przykładzie ActionMailer::Base). W pewnym momencie twój kod jest przeładowywany i teraz ActiveRecord nadal zawiera ten moduł, mimo że railsy myślą, że go wyładował. Błąd występuje, gdy odwołujesz się do dzierżawcy, ponieważ powoduje to, że szyny uruchamiają swoje const_missingpunkty zaczepienia, aby dowiedzieć się, skąd dzierżawca powinien zostać załadowany, a ten kod przestaje działać, ponieważ moduł, od którego rozpoczyna się ciągłe wyszukiwanie, nie powinien tam być.

Istnieją 3 możliwe rozwiązania:

  1. Przestań włączać swój moduł do klas, których nie można przeładowywać - albo dołącz do indywidualnych modeli, kontrolerów w razie potrzeby, albo utwórz abstrakcyjną klasę bazową i dołącz do niej moduł.

  2. Spraw, aby ten moduł nie był przeładowywalny, przechowując go w miejscu, które nie znajduje się w autoload_paths (będziesz musiał go jawnie wymagać, ponieważ szyny nie będą już ładowały go magicznie)

  3. Zmiana Tenant na: Tenant ( Object.const_missingzostanie wywołana, a nie Tenant.const_missing)

Frederick Cheung
źródło
30
Wydaje mi się, że znalazłem trzecie rozwiązanie, chociaż zastanawiałem się, czy wiesz, dlaczego to działa. Jeśli mam na myśli: Najemca, wszystko działa magicznie. Być może dlatego, że ładuje go jako stałą najwyższego poziomu? Może?
kddeisz
3
to Object.const_missing zostanie wywołany, a nie YourModule.const_missing, więc wszystko powinno się ułożyć
Frederick Cheung
6
Wycofanie się na najwyższy poziom też ::działało dla mnie!
Alex Moore-Niemi
7
Miałem ten problem, który pojawiał się od czasu do czasu iw moim przypadku był związany ze sprężyną, więc robienie tego ./bin/spring stopbyło jego rozwiązaniem.
santuxus,
2
Uwielbiam to, że jest to błąd środowiska wykonawczego Ruby / Rails - w przeciwieństwie do innych języków, dynamicznych lub nie, Ruby daje programistom prawdziwą nieograniczoną elastyczność, dzięki której nie mają pojęcia, gdzie moduły są definiowane, dopóki program nie zostanie uruchomiony (iw jakiej kolejności jest wykonywany). Jest tak dobrze zaprojektowany.
Andy Ray
32

Zmiana ModuleName na :: ModuleName działała dla mnie.

Aman Kumar
źródło
6

Nie jestem pewien, czy to komuś pomoże, ale nagle zaczęło się to dziać po zmianie, która wydawała się niezwiązana. Zniknął po zrestartowaniu serwera aplikacji.

beef_boolean
źródło
0

Zmiana, ModuleNameaby 'ModuleName'.constantizerozwiązać problem za mnie.

Qortex
źródło
0

Co mi pomogło:

Zaktualizuj config.eager_load = falsedotrue

w config/environments/development.rb

Ruby 2.6.5
Rails 5.1.6

Jan Werkhoven
źródło
1
Tak, zdecydowanie tego nie rób. To zabije twoją zdolność do ponownego ładowania kodu w trakcie opracowywania.
kddeisz
-13

Czasami po prostu

Uruchom ponownie serwer,

Albert.Qing
źródło
Nie rozumiem, dlaczego przeczuwam tę odpowiedź? Powtarzanie oznacza, że ​​to ważne! Dlaczego proste rzeczy mają wiele bzdur?
Albert, Qing
7
Jest to odrzucane, ponieważ (a) bez względu na to, ile razy zrestartujesz serwer, nie rozwiąże to problemu z pierwotnego pytania i (b) nie powinieneś po prostu leczyć symptomów problemu, ale sam problem.
tjbp
@tjbp plz uważaj na słowo „czasami” ok?
Albert, Qing
problem polega na tym, że nie można debugować aplikacji w trybie deweloperskim, jeśli po każdej zmianie trzeba restartować serwer.
Max Ivak
2
Zagłosuję za tą odpowiedzią, ponieważ jeśli używasz mongoid i usuniesz obiekt X z konsoli rails, pojawi się ten błąd: A copy of X has been removed from the module tree but is still activena wszystkich stronach, które mają Object Y.embeds Xi restart serwera, naprawdę działa w tym konkretnym przypadku. Ale powinieneś zmienić swoją odpowiedź.
Lucas Andrade