我们有两个Rails模型:Person
和Administrator
。我们不允许在模型级别删除Administrator
:
class Person < ActiveRecord::Base
end
class Administrator < Person
def destroy
raise "Can't remove administrators."
end
end
me = Administrator.new
me.destroy # raises an exception
我希望能够在测试期间解决这个问题,但仅限于在安装和拆卸过程中创建的特定实例。我不想改变班级的行为,因此class_eval
和remove_method
是不可行的。
我尝试重新定义实际的实例#destroy
方法:
def me.destroy
super
end
或在单身类上重新定义它:
class << me
def destroy
super
end
end
但那些仍然提出异常。我无法弄清楚如何让它隐式调用超类方法。我最终创建了自己的destroy!
方法(因为它实际上并不是ActiveRecord中的方法),这违反了我不改变类行为的愿望:
def destroy!
ActiveRecord::Persistence.instance_method(:destroy).bind(self).call
end
有没有简单的方法来告诉单个实例方法调用它的超类方法?
最终答案:根据Holger Just链接的文章,我能够简单地明确调用超类方法:
def me.destroy
self.class.superclass.instance_method(:destroy).bind(self).call
end
答案 0 :(得分:3)
我会尝试重构这种行为,使其更加适合测试。例如。你可以允许一个可选参数来破坏,例如i_know_what_im_doing
必须设置为true才能执行销毁。或者,你可cancel destroy
before_destroy
挂钩
class Administrator < Person
def before_destroy(record)
# You can't destroy me
false
end
end
在测试中,您可以调用Administrator.skip_callback :before_destroy
来忽略它并进行适当的破坏。
最后,您可以在测试中覆盖/存根方法。虽然您说您不想修改类的行为,但您仍然需要这样做(并且今天使用destroy!
方法隐式执行此操作)。
答案 1 :(得分:1)
我不熟悉Ruby元编程,所以如果你可以在一个实例上调用超类的方法而不修改它,我就不会回答。但是您可以使用alias
创建一个超类方法的挂钩:
class Administrator < Person
alias :force_destroy :destroy
def destroy
raise "Can't remove administrators."
end
end
这样,admin.destroy
会引发异常,但admin.force_destroy
实际上会调用ActiveRecord。