在Rails中扩展Ruby宝石

6
假设我有一个Rails应用程序,其大部分功能都来自于一个gem(例如CMS)。
现在如果我需要添加一些自定义内容(例如,为用户添加属性),最佳实践是什么?如果我对gem进行定制,则将来更新gem时会遇到问题。
如何处理这种情况是最佳的方法?

我正在尝试做非常类似的事情。但愿我有一个代码示例,可以解释如何做到这一点。 - Andrew
2个回答

17

这个问题相当久远,但我认为它需要更详细的解释。确实你可以在运行时修改rails(和ruby)的代码,也就是重新打开一个类或模块并注入新的代码。然而,在rails中由于所有的动态类加载和卸载都是在开发模式下进行的,所以这有些棘手。

我不会深入探讨,但你真的应该把扩展放到一个初始化器或gem中,因为它们在开发模式下的请求之间会被重新加载。如果将代码放入插件中,它将无法重新加载,并且你将会遇到非常神秘的错误,例如“已从模块树中删除了XXX的副本,但其仍然处于活动状态!”

最简单的方法是将代码放入一个初始化器中(例如config/initializers/user_extensions.rb)。你可以使用class_eval来注入代码。

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

Ruby 的可扩展性的一个主要缺点是追踪代码来自何处。您可能希望添加某种关于加载扩展的日志消息,以便人们可以追踪到它。

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

进一步阅读:

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


非常好的答案,帮了我很大的忙!但我有一个疑问,将 ...新代码... 与在config/initializers/user_extensions.rb中使用'require Rails.root.join("app", "models", "user")',然后在app/models/user.rb中打开类并定义 ... 新代码...之间只是外观上的区别吗? - ilasno

1
Ruby允许您在运行时扩展类,因此您通常可以在不触及源代码的情况下对库进行修改。否则,我建议您下载gem,在库中创建一些钩子,并将其作为补丁提交回去。
更新:
请注意,这些自定义是特定于应用程序的。
是的。我的意思是以某种方式修改通用API,使其可以根据应用程序进行自定义。例如,通过允许用户向某些方法传递块等。

请注意,这些自定义内容是特定于应用程序的。 - Neil Middleton

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接