开发者

Extending a ruby gem in Rails

开发者 https://www.devze.com 2022-12-15 09:44 出处:网络
Let\'s say I have a Rails app that gets most of it\'s functionality from a gem (for instance, a CMS).

Let's say I have a Rails app that gets most of it's functionality from a gem (for instance, a CMS).

If I now need to add some customisation (for instance, add a property to a user) what is the best practice way of doing this? If I customise the gem, then I will have issues with updating the gem in the futu开发者_运维技巧re.

What is the best approach to take here?


This question is quite old, but I feel it could use a bit more fleshing out. It is true that you can monkeypatch rails (and ruby) at run-time. That means it's easy to reopen a class or module and inject new code. However, this is somewhat trickier in rails due to all the dynamic class loading and unloading that goes on development mode.

I won't go into details, but you really want to put your extensions into an initializer, or a gem, since they get reloaded between requests in dev mode. If you put the code into a plugin it won't get reloaded and you'll get very mysterious errors such as "A copy of XXX has been removed from the module tree but is still active!"

The easiest thing to do is throw the code into an initializer (e.g. config/initializers/user_extensions.rb). You can just use class_eval to inject the code.

User.class_eval do
  ... new code ...
end

One major drawback of ruby's extensibility is tracking down where code is coming from. You might want to add some kind of log message about the extensions being loaded, so people can track it down.

Rails.logger.info "\n~~~ Loading extensions to the User model from #{ __FILE__ }\n"
User.class_eval do
  ... new code ...
end

Further reading:

http://airbladesoftware.com/notes/monkey-patching-a-gem-in-rails-2-3


Ruby allows you to extend classes in runtime, so you can often hack in to a library without touching the source code. Otherwise I would suggest that you download the gem, create some hooks in the library and submit that back as a patch.

Update:

Note that these customisations are application specific

Yes. What I meant was to modify the generic api in a way, such that it is possible to customise per application. For example, by allowing the user to pass a block to certain methods etc.

0

精彩评论

暂无评论...
验证码 换一张
取 消