I'm monkey-patching a Rails engine with something like:
SomeClass.class_eval do
# ...
end
The first time I hit the web site, on development mode at least, it works, but the second time it's like my patch never existed. I presume it's Rails auto-reloading the engine (which is installed in vendor/) and not reloading my code. This is Rails 2.3.
Any ideas how to do it so that my code also gets reloaded?
I just wrote my first monkey-patch, and so needed to come up with a set of conventions around it. Here's what I came up with:
Place your extensions under
lib/ext/
. (Suggested by veteran workmad3 in #rubyonrails IRC room.) In my case, I'm adding a method to theMail::Message
class (from themail
gem, used by ActionMailer), so I created:/lib/ext/mail/message.rb
Open the class or module and add your code:
module Mail class Message def to_is_phone? !!(self.to.first =~ /^\+1\d{10}$/) end end end
Create an initalizer to load all your monkey-patches. Rails will autoload a file when a constant is referenced, but since you're adding methods to existing classes/modules rather than defining new ones, that won't work, so you have to manually require all your monkey-patches. So I created:
/config/initializers/monkey_patches.rb
Which contains:
require 'ext/mail/message'
It's ugly, but I found that if I put this kind of code at the bottom of environments.rb it always guaranteed correct load-order on startup.
EDIT: This solution only works for Rails 3+ since it's dependent on some functionality in Rails::Railtie. Put this code in an initializer.
This question is quite old, but here's a solution I found:
This forces Rails to reload the class on every request in development mode, but only once in production.
Have a look at how this gem handles "decorating" aka monkey patching something in an engine or vice versa:
https://github.com/EPI-USE-Labs/activesupport-decorators
If you place the patch in any .rb file inside /config/initializers, it should work.
Unfortunately, there is no way to hook into the reloading mechanism of Rails 2.x. What you could do, is place your patch somewhere in the app or lib directory. (
lib/core_ext
is probably the preferred location). Then add the directory to the autoload_paths in your config.You might also need to open the class, rather than using class_eval.