how do i validate the presence of a field only if another field was edited in rails?
I have a table with a column called lifecycle_id, and another called lifecycle_change_reason. lifeycle_id 开发者_如何学Cis normally changed automatically by the system based on other factors, but certain users have the ability to change the lifecycle manually. if they do, I would like to require them to provide a reason for the change, but I don't want to require that field any other time. does anyone have a suggestion for how I can perform this type of validation?
thx :)
-C
I can see a couple different ways. I think the best would be to add another field to the table called something like lifecycle_id_original
. Then your model would include code like this:
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
When the object (member in this example) is validated, lifecycle_change_reason will only be required when the original and lifecycle_id are not identical. A nil value is also allowed for the original, because that's what it'll be when a record is newly created.
Then when it is saved, the "original" is set to match the lifecycle_id, so the next update cycle will work properly.
This isn't as clean as I'd like. My first thought was to use an attr_accessor
so the duplicate isn't being stored in the DB all the time, but that would have meant setting that value every time a record is loaded. I'm not aware of any on_load style callbacks for ActiveRecord models.
This seems like what the controller is for. I realize that people want to push logic to models, and for good reason, but let's be pragmatic here: if your system is changing this value automatically, and there is only a single point in your system where someone can change it manually, it does not, in my opinion, introduce all that much complexity to simply enforce the existence of a reason in your controller with something simple like:
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
精彩评论