Perché include i malfunzionamenti delle inizializzatori del motore Rails quando cache_classes = false?

StackOverflow https://stackoverflow.com/questions/5852580

  •  27-10-2019
  •  | 
  •  

Domanda

Ho un motore che sta estendendo le lezioni di un altro motore nei suoi inizializzatori come così:

module MyApp
    class Engine < ::Rails::Engine
        initializer 'extend Product' do
            AnotherApp::Product.send :include, MyApp::ProductExtender
        end
    end
end

Il ProductExtenderIl modulo chiama alcuni metodi sull'altro app :: Prodotto quando è incluso, ad es.

module ProductExtender
    def self.included( model )
        model.send :include, MethodsToCall
    end

    module MethodsToCall
        def self.included( m )
            m.has_many :variations
        end
    end
end

Funziona in ambienti di prova e produzione, ma quando config.cache_classes = false, lancia un NoMethodError Da me quando provo a chiamare qualcosa definito dal productExder, come @Product.Variations.

Inutile dire che è agghiacciante vedere tutti i miei test passare e poi essere sbattuti con un errore nello sviluppo. Non succede quando ho impostato cache_classes = true, ma mi chiedo se sto facendo qualcosa che non dovrei essere.

La mia domanda è duplice: Perché ciò sta accadendo e c'è un modo migliore per raggiungere questa funzionalità di estensione/metodi di chiamata sull'oggetto di un'altra applicazione?

Ringrazia tutti!

È stato utile?

Soluzione

Sono riuscito a risolvere questo problema usando a to_prepare Blocca invece dell'inizializzatore. Il to_prepare Block si esegue una volta in produzione e prima di ogni richiesta di sviluppo, quindi sembra soddisfare le nostre esigenze.

Non era ovvio quando stavo facendo ricerche Rails::Engine Dal momento che è ereditato da Rails::Railtie::Configuration.

Quindi, invece del codice nella domanda, avrei:

module MyApp
    class Engine < ::Rails::Engine
        config.to_prepare do
            AnotherApp::Product.send :include, MyApp::ProductExtender
        end
    end
end

Altri suggerimenti

Cache_Classes ha in realtà un nome fuorviante: non c'è cache. Se si imposta questa opzione su False, Rails scarica esplicitamente il codice dell'applicazione e la ricarica quando necessario. Ciò consente alle modifiche apportate in sviluppo per avere un effetto senza dover riavviare il processo (server).

Nel tuo caso, un altro prodotto :: Product viene ricaricato, così come ProducTender, ma l'inizializzatore non viene nuovamente licenziato, dopo la ricarica, quindi un altro prodotto :: Prodotto non è "esteso".

Conosco molto bene questo problema e ho finito per eseguire il mio ambiente di sviluppo con cache_classes = true e occasionalmente riavviare il mio server. Non avevo tanto sviluppo da fare su motori/plugin, quindi questo era il modo più semplice.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top