Why doesn't inclusion in Rails Engine initializers work if cache_classes = false?

I have an engine that extends the Engine classes in its initializers like this:

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

The ProductExtender module calls some methods in the AnotherApp :: Product file when it is enabled, for example

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

This works in test and production environments, but when config.cache_classes = false it throws me a NoMethodError when I try to call something specific ProductExtender like @ product.variations.

Needless to say, it’s cold to see that all my tests pass, and then slam shut with a development error. This does not happen when I set cache_classes = true , but it makes me wonder if I am doing something that I should not be.

My question is twofold: Why is this happening, and is there a better way to achieve this functionality of extension / call methods for another application object?

Thanks everyone!

+6
source share
2 answers

I managed to solve this problem using the to_prepare block instead of the initializer. The to_prepare block to_prepare executed once during the production process and before each development request, so it seems to meet our needs.

This was not obvious when I studied Rails::Engine , as it is inherited from Rails::Railtie::Configuration .

So, instead of the code in the question, I would:

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

cache_classes is actually a misleading name: no caching. If you set this parameter to false, the rails explicitly unload your application code and reload it if necessary. This allows you to make changes that you make during the development process, without the need for a restart (server).

In your case, AnotherApp :: Product restarts, like ProductExtender, but the initializer does not start again after a reboot, so AnotherApp :: Product is not "advanced".

I know this problem very well and ended up working with my development environment with cache_classes = true and sometimes I restart my server. I have not developed much for the engines / plugins, so this was the easiest way.

0
source

Source: https://habr.com/ru/post/887083/


All Articles