rahum
rahum

Reputation: 121

execute before_validation between other validations?

I've got a before_validation in a model. Its purpose is to calculate the time worked between two DateTime objects, and insert that value into a time_worked attribute. Its success depends on the validity of two fields, and it spits out the value of a third field which, in turn, has validations.

class TimeEntry < ActiveRecord::Base
  validates :start_time, :end_time, :presence => true
  validates :time_worked, :presence => true, :numericality => true
  before_validation :calculate_time_worked

def calculate_time_worked
    time_float = (Time.parse(self.end_time.to_s) - Time.parse(self.start_time.to_s)) / 1.hour  
    self.time_worked = ((time_float * 10).ceil).to_f/10
end

The problem is that my calculate_time_worked method will fail if either start_time or end_time are empty or invalid, which is exactly why those two fields have validations!

Any ideas how to refactor?

Upvotes: 0

Views: 149

Answers (2)

Jesse Wolgamott
Jesse Wolgamott

Reputation: 40277

The before_save solution from @PedroMedeiros will work in this case.... but if you wanted to validate that time_worked is positive, then you would probably do something like this:

  validate :calculate_time_worked

  def calculate_time_worked
    return if end_time.blank? || start_time.blank?
    time_float = (Time.parse(self.end_time.to_s) - Time.parse(self.start_time.to_s)) / 1.hour  
    self.time_worked = ((time_float * 10).ceil).to_f/10
    if time_worked < 0
      self.errors.add(:end_time, "Must be after Start Time")
    end
  end

Finally -- this SO question is cool on getting the difference of time in hours

Upvotes: 1

Pedro Medeiros
Pedro Medeiros

Reputation: 171

it seens that before_validates is called just before those methods are sets. If I where you I would use before_save to calculate_time_worked. once the attrs will set and your validations will be completed.

class TimeEntry < ActiveRecord::Base
  validates :start_time, :end_time, :presence => true
  validates :time_worked, :presence => true, :numericality => true
  before_save :calculate_time_worked

end

Upvotes: 0

Related Questions