Rails 3 - 扩展gem或插件中存在的模型

时间:2011-10-04 14:02:16

标签: ruby-on-rails ruby model-view-controller content-management-system

在RefineryCMS gem中,有一个Page模型,用于从CMS中提取信息。该模型未在您当前的应用程序中定义,因此您无法修改其代码(除非您跳转到gem代码中)。

有没有办法在现有模型中修改方法而不必在每次加载页面时都应用更改?这是我尝试过的:

  1. Model.class_eval

  2. Model.send:include,MixinThatHasNewMethods

  3. 我也尝试使用更新的方法创建一个新类,希望能更新现有的类。

    有什么想法吗?

2 个答案:

答案 0 :(得分:4)

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文件夹)。

这里重点是代码的加载顺序,修改应该在真正的类代码之后加载。

那是在你的lib或初始化器中(不是一个好地方但它有效)你应该把你的custom方法放在Model类中。

编辑:我正在再次阅读你的问题,我不得不提到,你错了,你实际上可以从宝石或插件中改变一个类。 ruby加载同一范围内的每个对象,并且可以覆盖所有对象。

在开发环境中,RoR会在每个请求上重新加载所有类(除非cache_classes = false)。有可能,在第一次请求之后,重新加载gem并且您的更改将丢失。请注意在每次请求后重新加载您的库(仅在开发环境中)

PS:include& class_eval也可以工作,重要的是太覆盖以前加载的类

答案 1 :(得分:0)

如果我理解你的问题,你可以这样做。

您可以按如下方式覆盖模型。假设您有以下课程:

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”课程。