简体   繁体   中英

Rails 3 - Extending a model that exists in a gem or plugin

In the RefineryCMS gem there is a Page model that is used to pull in information from the CMS. The model is not defined in your current app and therefore you cannot modify its code (unless you hop into the gem code).

Is there a way to modify the methods within an existing model without having to apply the changes each time a page is loaded? Here is what I have tried:

  1. Model.class_eval

  2. Model.send :include, MixinThatHasNewMethods

I've also tried creating a new class with the updated methods and hoping that would update the existing class.

Any ideas?

Ruby allows the developer to "update" any object, at anytime.

That means that after Model is loaded by RefineryCMS you can just reopen the class and update it:

class Model
    def new_method(value)
        ...
    end

    def existing_method(*args)
        ...
        super  # refer to the ovewriten method
    end
end

In your case RafineryCMS is an RoR app, that means while loading the server the ruby code is loaded first for the rails framework, then for the RafineryCMS gem/plugin and after all for your custom libraries (eg: lib folder).

The important point here is the loading order of the code, modification should be loaded after the genuine class code.

That is in your lib or initializers (not really a good place but it works) you should put your custome methods for the Model class.

EDIT: I was reading your question again, and I have to mention, that you are wrong, you actually can change a class from a gem or plugin. ruby load every object in the same scope and all objects are accessible to be overwritten.

In development environment, RoR, reloads all classes (except if cache_classes = false) on every request. It is possible, that after the first request, the gem is reloaded and your changes are lost. Take care to reload your libraries after for every request (only in developement env)

PS: include & class_eval would work too, the important thing is too overwrite a previously loaded class

If I understand your question correctly, you can do something like this.

You may override the model as follows. Say you have the following class:

class User
 def name user_name
  p "my name is #{user_name}"
 end

 def age my_age
   p "age - #{my_age}"
 end

end

then you can call this class by:

user = User.new
user.name "sameera"
user.age 30

and you will get the output:

"my name is sameera"
"age - 30"

then say you want to change only the behavior of the ' name ' method, the you can re-create the user class and add only that method as follows:

class User
 def name user_name
   p "my modified name #{user_name}"
 end 
end

and still you can call both the methods as follows:

user = User.new
user.name "sameera"
user.age 30

But this time, your output will be:

"my modified name sameera"
"age - 30"

I think you got my point, hope this helps.

**NOTE: make sure you call the modified ' User ' class before you load the original User class.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM