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?
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:
Rails.configuration.to_prepare do
SomeClass.class_eval do
# ...
end
end
This forces Rails to reload the class on every request in development mode, but only once in production.
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 the Mail::Message
class (from the mail
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'
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.
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.
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