【问题标题】:Rails 3 - Extending a model that exists in a gem or pluginRails 3 - 扩展存在于 gem 或插件中的模型
【发布时间】:2011-11-30 17:41:14
【问题描述】:
在 RefineryCMS gem 中有一个页面模型,用于从 CMS 中提取信息。该模型未在您当前的应用程序中定义,因此您无法修改其代码(除非您跳入 gem 代码)。
有没有一种方法可以修改现有模型中的方法,而不必在每次加载页面时都应用更改?这是我尝试过的:
Model.class_eval
Model.send :include, MixinThatHasNewMethods
我还尝试使用更新的方法创建一个新类,并希望这会更新现有的类。
有什么想法吗?
【问题讨论】:
标签:
ruby-on-rails
ruby
model-view-controller
content-management-system
【解决方案1】:
如果我正确理解你的问题,你可以这样做。
您可以按如下方式覆盖模型。假设您有以下课程:
class User
def name user_name
p "my name is #{user_name}"
end
def age my_age
p "age - #{my_age}"
end
end
那么你可以通过以下方式调用这个类:
user = User.new
user.name "sameera"
user.age 30
你会得到输出:
"my name is sameera"
"age - 30"
然后假设您只想更改“name”方法的行为,您可以重新创建用户类并仅添加该方法,如下所示:
class User
def name user_name
p "my modified name #{user_name}"
end
end
您仍然可以按如下方式调用这两种方法:
user = User.new
user.name "sameera"
user.age 30
但这一次,你的输出将是:
"my modified name sameera"
"age - 30"
我想你明白我的意思了,希望这会有所帮助。
**注意:确保在加载原始 User 类之前调用修改后的“User”类。
【解决方案2】:
Ruby 允许开发人员随时“更新”任何对象。
这意味着在 RefineryCMS 加载 Model 之后,您可以重新打开该类并对其进行更新:
class Model
def new_method(value)
...
end
def existing_method(*args)
...
super # refer to the ovewriten method
end
end
在您的情况下,RafineryCMS 是一个 RoR 应用程序,这意味着在加载服务器时,首先为 rails 框架加载 ruby 代码,然后为 RafineryCMS gem/插件加载,最后为您的自定义库(例如:lib 文件夹)加载。
这里重点是代码的加载顺序,修改要在正版类代码之后加载。
这是在您的库或初始化程序中(不是一个很好的地方,但它可以工作)您应该将您的自定义方法放在 Model 类中。
编辑:我再次阅读您的问题,我不得不提一下,您错了,您实际上可以从 gem 或插件更改一个类。
ruby 加载同一范围内的每个对象,并且所有对象都可以被覆盖。
在开发环境中,RoR 会在每次请求时重新加载所有类(除非 cache_classes = false)。在第一次请求之后,gem 可能会重新加载并且您的更改会丢失。请注意在每次请求后重新加载您的库(仅在开发环境中)
PS:include & class_eval 也可以,重要的是覆盖了之前加载的类