问题
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?
回答1:
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.
回答2:
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'
回答3:
If you place the patch in any .rb file inside /config/initializers, it should work.
回答4:
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.
回答5:
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.
回答6:
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
来源:https://stackoverflow.com/questions/4460800/how-to-monkey-patch-code-that-gets-auto-loaded-in-rails