我不知道如何正确地标出标题,我认为解释这个问题的最好方法就是使用代码示例。
我想定义一个像这样的元方法(在Rails 5中):
class Post < ApplicationRecord
override_this_attribute_writer :some_attribute
end
override_this_attribute_writer
遵循一个共同模式,它通过在其上进行一些过滤来覆盖原始编写器。我发现这种覆盖方式非常方便和明确。
module MyCommonModule
extend ActiveSupport::Concern
module ClassMethods
def override_this_attribute_writer(attribute_name)
alias_method :"#{attribute_name}_old=", :"#{attribute_name}="
define_method :"#{attribute_name}=" do |a_value|
# Do my stuff
send(:"#{attribute_name}_old=", a_value)
end
end
end
执行此操作时,我在调用alias_method
时遇到异常,因为显然我尝试复制的方法尚不存在(还)。
module MyCommonModule
extend ActiveSupport::Concern
module ClassMethods
def override_this_attribute_writer(attribute_name)
define_method :"#{attribute_name}=" do |a_value|
# Do my stuff
send(:write_attribute, attribute_name, a_value)
end
end
end
我希望这不起作用:如果在运行元方法时,ActiveRecord尚未创建属性编写器,这意味着它将在稍后执行并覆盖我刚刚定义的方法。 /强>
但令人惊讶的是它奏效了!所以我把手放在ActiveRecord(5.1.5)中以了解更多信息。
我想确保我所做的事情是安全的并且不仅仅是偶然的工作:我调查了the definition of method writer,并将binding.pry
放在方法周围。
这是实验的结果:
object.attribute=
object.attribute=
时,仍然会调用我自己的方法代替ActiveRecord 所以,这是我不明白的:如果ActiveRecord似乎覆盖了我的方法,但它没有,是什么阻止它做呢?
最后我需要知道的是,我所做的修复实际上是一个好的做法(并且是强大的),还是存在风险,如果将来我们进行升级,它可能会破坏。
如果您认为我的修复很危险,您能否提出不同的方法来实现同一目标?
答案 0 :(得分:2)
调用super
更加惯用:
module MyCommonModule
extend ActiveSupport::Concern
module ClassMethods
def override_this_attribute_writer(attribute_name)
define_method :"#{attribute_name}=" do |value|
# do some stuff
super value
end
end
end
end