Reputation: 10421
I have two attributes (hours and days) in my model (auction). I have business logic on the combination of hours and days. For example
auction duration = days*24 + hours
I also have some basic validation on hours and days:
class Auction < ActiveRecord::Base
validates :days,:presence => true, :numericality => { :greater_than_or_equal_to => 0, :only_integer => true }
validates :hours,:presence => true, :numericality => { :greater_than_or_equal_to => 0, :only_integer => true }
I would like to incorporate my business logic into the validation, such that hour and days cannot both be zero. Is there a way to do this with an ActiveRecord validation? I know there are other ways to do this w/out an AR validation. Right now I am creating a new instance of my model. Validating days and hours as above. Then I have a model method that "manually" does the validation and removes the instance if it doesn't pass. I know this is not the best way to do this
def compute_end_time
# assumes that days and hours are already valid
time = self.days*24 + self.hours
if time > 1
self.end_time = time.hours.from_now.utc
self.save
else
# Auction duration too short (i.e. zero)
self.delete
end
end
Upvotes: 0
Views: 566
Reputation: 10421
So my final solution was an extension of @rharrison33:
validates :days,:presence => true, :numericality => { :greater_than_or_equal_to => 0, :only_integer => true }
validates :hours,:presence => true, :numericality => { :greater_than_or_equal_to => 0, :only_integer => true }
validate :days_and_hours
def days_and_hours
# It may not validate days and hours separately before validating days_and_hours,
# so I need to make sure that days and hours are both not NIL before trying to compute 'time'
# I also only want to compute end_time if it has not been computed yet
if (!self.days.nil? && !self.hours.nil?)
if (self.end_time.nil?) # if end_time has not yet been computed
if (self.days == 0 && self.hours == 0)
self.errors[:base] << "Days and hours can not be zero."
else
time = self.hours + self.days*24
self.end_time = time.minutes.from_now.utc
self.setStatus # validate status after end time is set
end
end
end
end
Upvotes: 0
Reputation: 408
You can check for a value greater than 0 by using the numericality validator:
validates :auction_duration, :numericality => { :greater_than => 0 }
More info is at: http://guides.rubyonrails.org/active_record_validations_callbacks.html#numericality
Upvotes: 0
Reputation: 1282
You need to write a private validate function something like this.
class Auction < ActiveRecord::Base
validates :days,:presence => true, :numericality => { :greater_than_or_equal_to => 0, :only_integer => true }
validates :hours,:presence => true, :numericality => { :greater_than_or_equal_to => 0, :only_integer => true }
validate :days_and_hours
private
def days_and_hours
if !(days && hours)
errors.add_to_base("Days and hours can not be zero. Thank you.")
end
end
end
Upvotes: 2