我正在开发一个在线商店,客户需要能够删除订单并让其产品自动重新进货(例如,用于测试订单)。这是我第一次尝试实现这个:
class Order < ActiveRecord::Base
def destroy_and_restock
restock_products
destroy
end
protected
def restock_products
line_items.each do |li|
li.product.quantity_on_hand += li.quantity
li.product.save
end
end
end
但是如果我以后需要创建另一个destroy_and_x
方法呢?为什么不允许将X作为参数传递给destroy()
方法?所以现在我想考虑这个:
alias :old_destroy :destroy
def destroy(options = {})
if options['restock'] == true
restock_products
end
old_destroy
end
protected
def restock_products
line_items.each do |li|
li.product.quantity_on_hand += li.quantity
li.product.save
end
这是更具可扩展性,但让我觉得有点脏。感觉脏了我错了吗?有没有更好的方法呢?
答案 0 :(得分:2)
我会说“是的,这很脏。”您的目的不是要修改'destroy'方法的行为,而是要做一些特定于域的工作,然后运行destroy
。您的第一种方法很棒 - 定义一个可以满足您需求的方法,并根据需要调用destroy
。我认为,正如您所考虑的那样,“包装”或“猴子修补”方法是一种在无法使用标准OO方法时最佳应用的技术 - 例如,当您需要修改/增加行为时在您的控制范围之外定义和使用的类。
即使你 考虑修改destroy
方法本身的行为,我建议覆盖这里的方法,而不是包装它:< / p>
def destroy(options = {})
restock_products if options['restock']
super() # I think parens are necessary here, to avoid passing options up the chain
end
答案 1 :(得分:0)
如何使用一个块?然后你在课堂上设计时不必拉开头发,你可以在需要的时候做更多的事情:
def destroy_after &block
yield if block
destroy
end
然后这样称呼:
order.destroy_after { order.restock_products }
我想不出这个功能的好名字......但我希望你明白这个想法。
答案 2 :(得分:0)
http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
现在您可以保护您的方法并添加尽可能多的before_destroy事物。希望这对你有用而不会超越毁灭。
祝你好运。
答案 3 :(得分:0)
如果猴子修补不能让你在晚上睡觉,你可以通过子类化来实现同样的目的。当我需要快速入侵或快速调试时,我也会修补补丁。