在第一篇中我们讨论了如何控制model的hook流.
但是其实其中还是有未考虑到的地方,比如在新建一个model对象的时候,会报错:
ActiveRecord::ActiveRecordError: can not update on a new record object
意思是你不能在一个新建对象上调用update方法!
对应的代码如下:
def was_deleted=(new_val)
unless self.was_deleted
update_column(:was_deleted,new_val)
end
end
无疑在update和new时都会调用该方法,所以我们必须搞清楚到底是什么原因然后才能做出处理.恰好rails提供一个changed?方法,官方的解释为:
Returns true if any of the attributes have unsaved changes, false otherwise.
注意是unsaved changes!!!如果是新建那么changed?自然返回true,所以我们重构如下:
def was_deleted=(new_val)
unless self.was_deleted
if !changed?
update_column(:was_deleted,new_val)
else
#do something ...
end
end
end
问题是在else中做点什么,如果啥都不做was_deleted属性不会更新的哦!
第一次尝试如下:
alias :"was_deleted=" :"org_was_deleted="
def was_deleted=(new_val)
unless self.was_deleted
if !changed?
update_column(:was_deleted,new_val)
else
org_was_deleted=(new_val)
end
end
end
看上去不错,但实际运行会报错,提示找不到org_was_deleted=方法,因为org_was_deleted=是was_deleted=的别名,所以实际就是找不到was_deleted=方法!?你可能会奇怪,如果没有这个方法为什么会调用自定义的方法呢???
其实很简单,该model类中的确没有对应的was_deleted=方法,该方法是ActiveRecord::Base类(或其超类)自动生成的,所以我们不用操心自己创建别名了,只要简单的调用super即可,最终的代码如下:
def was_deleted=(new_val)
unless self.was_deleted
if !changed?
update_column(:was_deleted,new_val)
else
super
end
end
end