【发布时间】:2011-01-06 09:54:55
【问题描述】:
我有一个表,其中有一列名为生命周期_id,另一列名为生命周期变化_原因。 lifeycle_id 通常由系统根据其他因素自动更改,但某些用户具有手动更改生命周期的能力。如果他们这样做,我想要求他们提供更改的原因,但我不想在其他时间要求该字段。有人对我如何执行这种类型的验证有建议吗?
谢谢 :)
-C
【问题讨论】:
我有一个表,其中有一列名为生命周期_id,另一列名为生命周期变化_原因。 lifeycle_id 通常由系统根据其他因素自动更改,但某些用户具有手动更改生命周期的能力。如果他们这样做,我想要求他们提供更改的原因,但我不想在其他时间要求该字段。有人对我如何执行这种类型的验证有建议吗?
谢谢 :)
-C
【问题讨论】:
我可以看到几种不同的方式。我认为最好将另一个字段添加到表中,称为lifecycle_id_original。然后您的模型将包含如下代码:
class Member < ActiveRecord::Base
belongs_to :lifecycle
validates :lifecycle_change_reason, :if => :lifecycle_changed?
before_save :reset_original_lifecycle
protected
def lifecycle_changed?
self.life_cycle_id != self.lifecycle_id_original && !self.lifecycle_id_original.nil?
end
def reset_original_lifecycle
self.lifecycle_id_original = self.lifecycle_id
end
end
当对象(本例中的成员)被验证时,只有在原始和生命周期_id 不相同时才需要生命周期更改原因。原始值也允许使用 nil 值,因为这是新创建记录时的值。
然后在保存的时候,设置“original”来匹配lifecycle_id,这样下一个更新周期就可以正常工作了。
这不像我想要的那样干净。我的第一个想法是使用attr_accessor,这样副本就不会一直存储在数据库中,但这意味着每次加载记录时都要设置该值。我不知道 ActiveRecord 模型有任何 on_load 样式回调。
【讨论】:
这似乎是控制器的用途。我意识到人们希望将逻辑推送到模型中,这是有充分理由的,但在这里我们要务实:如果您的系统正在自动更改此值,并且您的系统中只有一个点可以手动更改它,它确实在我看来,不要引入所有复杂性来简单地强制控制器中存在一个原因,比如:
if params[:object_name][:life_cycle_id] != @object.life_cycle_id && params[:object_name][:life_cycle_change_reason].blank?
flash[:error] = "You must enter a reason for changing the life cycle."
redirect_to :back and return false # or whatever
end
【讨论】: