Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Old and new values for an attribute in ActiveRecord validation

In Ruby, how would I run a validation that says that a model attribute can only be X if it used to be Y? The example would be an attribute status that takes either in-progress or complete. I'd want to say when user marks the object status, it can always be marked in-progress, but it can only be marked complete if it was first marked in-progress.

validate :status_change

def status_change
  unless self.status == "complete" && #here i want to say self.status used to be "in progress" 
    errors[:base] << "Can only mark object complete after it was first marked in progress"
  end
end
like image 397
james Avatar asked Apr 29 '16 05:04

james


2 Answers

Please consider use ActiveModel::Dirty

It provides methods to track these changes.

before_update :status_change

def status_change
  unless status == "complete" && status_was == "in-progress" 
    errors[:base] << "Can only mark object complete after it was first marked in progress"
  end
end

Also it's not need to use self. keyword here.

like image 58
retgoat Avatar answered Oct 19 '22 23:10

retgoat


You can use the change tracking provided by rails for this. In particular status_was returns the previous value of status. You can also use status_changed to know where the status has been changed (or else you would prevent other changes to complete models)

Personally I don't massively like the idea of validations that depend on other things than the current set of attributes. You may find that using a state machine (for example aasm) is a better way of enforcing this sort of behaviour.

like image 34
Frederick Cheung Avatar answered Oct 19 '22 23:10

Frederick Cheung