I haven’t been able to find this advice anywhere else, so I am posting
here so that it may help another lost soul.
Some plugins have a problem: if a plugin applies a mixin directly to a
model in app/models, this mixin gets unloaded by rails after the first
request. This only happens in development mode. The symptom of this is
an application that works for the first request but fails on subsequent
A call to Dispatcher.to_prepare will get around this problem by
re-applying any mixin that modifies the core models on each request. In
production mode, the classes are not unloaded and so the mixin is only
“Normal” plugins don’t have this problem: they modify active record, and
then the core models call these extensions. When these core models are
reloaded by rails, the plugin code is then reloaded as well. The problem
only shows up when you want to modify a model in apps/model without
requiring any code change to that model.
This style of using plugins is not considered to be a good idea by many.
However, I am writing plugins that are designed exclusively for a
particular application. These plugins enable optional features of a
specific application–they do not try to modify the behavior of rails or
extend active record.
Here is the code:
(1) modify Engines:Plugin
def apply_mixin_to_model(model_class, mixin_module)
model_class = Kernel.const_get(model_class.to_s) # \ weird, yet
mixin_module = Kernel.const_get(mixin_module.to_s) # / required.
(2) in your plugin’s init.rb:
in this case, there is a model app/models/language.rb, and module
(3) this is what my language_extension.rb looks like:
count = Key.count_all
if count > 0
(Key.translated(self).count / count * 100.0).round.to_s + ‘%’
has_many :translations, :dependent => :destroy
Most the code in apply_mixin_to_model is not really required. But it
seemed to me a little repetitive to type this over and over again for
So, most the code in apply_mixin_to_model is just doing that repeated
stuff for you, so long as the submodules are named right (ie
The simple thing to do is just put:
In the plugin’s init.rb. But again, I am trying to get fancy, perhaps at
my own peril.
Hope that helps someone,