Копия xxx была удалена из дерева модулей, но все еще активна

129

Я почти уверен, что ошибка не имеет ничего общего с фактическим содержимым TenantIdLoaderмодуля. Вместо этого это как-то связано с ActiveSupportзависимостями.

Я не могу избавиться от этой ошибки. Из того, что я читал, это потому, что либо ActiveRecord::Baseперезагружается, либо Company::TenantIdLoaderперезагружается, и почему-то не сообщает об этом. Помогите, пожалуйста! Я действительно хотел бы иметь возможность обновиться до Rails 4.2.

РЕДАКТИРОВАТЬ

Теперь я узнал, что это потому, что я ссылаюсь на то, Tenantчто перезагружается автоматически. Однако мне нужно иметь возможность ссылаться на класс, так что кто-нибудь знает, как это обойти?

конфиг / application.rb

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

конфиг / Инициализаторы / company.rb

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

Библиотека / компания / 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
источник
3
Этот ответ вообще помогает? stackoverflow.com/questions/17561697/…
Уэйнн Лью
Вы уверены, что задействован класс Tenant? Если вы удалите те части кода, которые используют Tenant, вы все равно получите ошибку?
Фредерик Чунг
@WaynnLue да, я думаю, это причина, я просто не знаю, как это исправить.
kddeisz
@FrederickCheung У меня есть еще один файл, похожий на этот, который ошибается таким же образом, и он всегда ошибки в строке, связанной с Tenant, так что это было мое лучшее предположение.
kddeisz
1
Хотя вы здесь не используете Wisper в Rails, другим людям может быть полезно отметить, что Wisper вызывает эту проблему довольно постоянно, если вы не следуете советам в этом потоке: stackoverflow.com/questions/28346609/…
Стив Н.

Ответы:

182

Tenantэто своего рода отвлекающий маневр - ошибка возникнет, если вы укажете какой-либо бит приложения, который нужно загрузить с помощью const_missingуловки rails .

Проблема в том, что вы берете что-то перезагружаемое (ваш модуль), а затем включаете его во что-то не перезагружаемое ( ActiveRecord::Baseили, как в вашем предыдущем примере ActionMailer::Base). В какой-то момент ваш код перезагружается, и теперь в ActiveRecord этот модуль все еще включен, хотя rails думает, что он его выгрузил. Ошибка возникает, когда вы ссылаетесь на Tenant, потому что это приводит к тому, что rails запускает свои const_missingперехватчики, чтобы выяснить, откуда следует загружать Tenant, и этот код пугает, потому что модуля, с которого начинается постоянный поиск, не должно быть.

Есть 3 возможных решения:

  1. Прекратите включать свой модуль в неперезагружаемые классы - либо включите в отдельные модели, контроллеры по мере необходимости, либо создайте абстрактный базовый класс и включите в него модуль.

  2. Сделайте этот модуль не перезагружаемым, сохранив его где-нибудь, кроме autoload_paths (вам придется потребовать его явно, поскольку рельсы больше не будут загружать его волшебным образом для вас)

  3. Изменение арендатора на :: арендатора ( Object.const_missingтогда будет вызываться, а не Tenant.const_missing)

Фредерик Чунг
источник
30
Кажется, я нашел третье решение, хотя мне было интересно, знаете ли вы, почему оно работает. Если я назову его :: Tenant, все сработает волшебным образом. Возможно, потому, что он затем загружает его как константу верхнего уровня? Может быть?
kddeisz
3
тогда будет вызываться Object.const_missing, а не YourModule.const_missing, так что все должно получиться,
Фредерик Чунг,
6
У ::меня тоже сработал отказ от использования верхнего уровня !
Алекс Мур-Ниеми
7
У меня время от времени возникала эта проблема, и в моем случае она была связана с весной, поэтому я ./bin/spring stopрешил ее.
santuxus
2
Я люблю , что это среда Ruby / Rails ошибка - в отличие от любого другого языка, динамики или нет, Ruby дает разработчикам истинную неограниченную гибкость, чтобы иметь в буквальном смысле понятия , где модули не определены , пока ваша программа выполняет (и в какой заказ он выполняет). Он так хорошо спроектирован.
Энди Рэй
32

Изменение ModuleName на :: ModuleName сработало для меня.

Аман Кумар
источник
6

Не уверен, что это кому-то поможет, но у меня это внезапно начало происходить после изменения, которое казалось несвязанным. Он исчез после того, как я перезапустил сервер приложений.

beef_boolean
источник
0

Изменение ModuleNameк 'ModuleName'.constantizeрешаемой проблеме для меня.

Qortex
источник
0

Что сработало для меня:

Обновить config.eager_load = falseдоtrue

в config/environments/development.rb

Ruby 2.6.5
Rails 5.1.6

Ян Верховен
источник
1
Да, определенно не делай этого. Это убьет вашу способность перезагружать код в процессе разработки.
kddeisz
-13

Иногда ты просто

Перезагрузите ваш сервер,

Albert.Qing
источник
Я не понимаю, почему проголосовали против этого ответа? Повторение означает, что это важно! Почему в простых вещах много ерунды?
Albert.Qing
7
Это отклонено, потому что (а) независимо от того, сколько раз вы перезагружаете сервер, это не решит проблему в исходном вопросе, и (б) вы должны лечить не просто симптомы проблемы, а саму проблему.
tjbp 05
@tjbp, пожалуйста, будьте осторожны со словом "иногда", ладно?
Albert.Qing
проблема в том, что отладить приложение в режиме разработки невозможно, если после каждого изменения необходимо перезапускать сервер.
Макс Ивак
2
Я проголосую за этот ответ, потому что, если вы используете mongoid и удаляете объект X из консоли rails, вы получите эту ошибку: A copy of X has been removed from the module tree but is still activeна всех страницах, на которых есть Object Y.embeds X, и перезапуск сервера действительно работает для этого конкретного случая. Но вы должны отредактировать свой ответ.
Лукас Андраде