我不知道如何正确表达标题,我认为解释这个问题的最好方法就是使用代码示例。
我的目标
我想定义这样的元方法(在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
我原以为这样做行不通:如果在运行meta方法时,ActiveRecord还没有创建属性writer,
这意味着它将稍后执行,并重写我刚才定义的方法。
但令人惊讶的是,它居然奏效了!所以我把手放在ActiveRecord(5.1.5)中以了解更多信息。
深入了解ActiveRecord 5.1.5
我想确保我所做的一切是安全的,而不仅仅是偶然发生的:我调查了
the definition of method writer
,并放置
binding.pry
围绕方法。
这是实验的结果:
所以,这就是我不理解的:如果ActiveRecord似乎覆盖了我的方法,但它没有覆盖,那么是什么阻止它这样做呢?
我的问题
最后,我需要知道的是,我所做的修复实际上是一种良好的做法(而且很健壮),还是存在风险,如果将来我们进行升级,它可能会崩溃。
如果您认为我的解决方案很危险,您能否提出一种不同的方法来实现相同的目标?