Perché include i malfunzionamenti delle inizializzatori del motore Rails quando cache_classes = false?
-
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 ProductExtender
Il 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!
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.