问题
I am using a library that is implementing a belongs_to
association between two entries in a database. Since this is not the behaviour I need I want to override this method via prepend
. But pry tells me that the original method is still called. I double checked and I'm using ruby 2.0.
The code that gets prepended:
module Associations
module ClassMethods
[...]
#Add the attributeName to the belongsToAttributes
#and add a field in the list for the IDs
def belongs_to(attr_name)
@belongsToAttributes ||= []
@belongstoAttributes << attr_name
create_attr attr_name.to_s
attribute belongs_to_string.concat(attr_name.to_s).to_sym
end
def belongsToAttributes
@belongsToAttributes
end
end
def self.included(base)
base.extend(ClassMethods)
end
end
# prepend the extension
Couchbase::Model.send(:prepend, Associations)
I use this in this class:
Note: I also tried to directly override the method in this class but it still doesn't happen
require 'couchbase/model'
class AdServeModel < Couchbase::Model
[...]
#I tried to add the belongs_to method like this
#def belongs_to(attr_name)
# @belongsToAttributes ||= []
# @belongstoAttributes << attr_name
# create_attr attr_name.to_s
# attribute belongs_to_string.concat(attr_name.to_s).to_sym
# end
# def belongsToAttributes
# @belongsToAttributes
# end
end
When I check with pry it shows me that I end up in this method call:
def self.belongs_to(name, options = {})
ref = "#{name}_id"
attribute(ref)
assoc = name.to_s.camelize.constantize
define_method(name) do
assoc.find(self.send(ref))
end
end
Any pointer to what I'm doing wrong would be appreciated.
Edit: Ok I solved the problem like this:
self.prepended(base)
class << base
prepend ClassMethods
end
end
end
# prepend the extension
Couchbase::Model.send(:prepend, Associations)
Since Arie Shaw's post contains important pointers to solve this problem I will accept his answer. Although he missed the point about extending and prepending the method that I want to call. For a more detailed discussion about my trouble with prepending the methods please refer to this question.
回答1:
According to the pry trace you posted, the method you wanted to monkey patch is a class method of AdServeModel
, not a instance method.
The problem with your
Associations
module approach is, you are callingModule#prepend
toprepend
the module to the existing class, however, you wrote aself.included
hook method which will only be called when the module is included (not prepended). You should write Module#prepended hook instead.The problem with the directly overriding approach is, you were actually overriding the instance method, rather than the class method. It should be something like this:
require 'couchbase/model'
class AdServeModel < Couchbase::Model
class << self
# save the original method for future use, if necessary
alias_method :orig_belongs_to, :belongs_to
def belongs_to(attr_name)
@belongsToAttributes ||= []
@belongstoAttributes << attr_name
create_attr attr_name.to_s
attribute belongs_to_string.concat(attr_name.to_s).to_sym
end
def belongsToAttributes
@belongsToAttributes
end
end
end
来源:https://stackoverflow.com/questions/18682494/overriden-method-still-gets-called