自定义验证在验证后给出空白字段,这是不对的

时间:2015-04-08 12:35:58

标签: ruby-on-rails ruby ruby-on-rails-4

我的模型中有一个自定义验证:

class Appointment < ActiveRecord::Base
    #VIRTUAL ATTRIBUTES
    attr_accessor :start_date, :start_time, :duration

    #RELATIONSHIPS
    belongs_to :task

    #VALIDATIONS
    before_validation :convert_to_datetime
    before_validation :dur
    validates :duration, presence: true
    validate :is_date_nil
    validate :time_collision_validation, if: :is_appointments_not_empty
    validate :check_time
    after_save :save_start_date

    def is_appointments_not_empty
        Appointment.all.present? 
    end

    def check_time  
        start_at = Time.parse("#{@start_date} #{@start_time}") 
        if start_at < Time.now
            errors.add(:start_date, "Cannot input past times")
        end
    end

    def convert_to_datetime
        unless @start_date.blank? && @start_time.blank? 
            self.start_at = Time.parse("#{@start_date} #{@start_time}")         
        end
    end

    def dur
        if @start_date.present? && @start_time.present? && @duration.present?
            self.end_at = Time.parse("#{@start_date} #{@start_time}") + (@duration.to_f*60*60)
        end
    end

    def time_collision_validation
        appointments = Appointment.all


        if @start_date.present? && @start_time.present? && duration == 0.to_s
            start_at = Time.parse("#{@start_date} #{@start_time}") 
            end_at = Time.parse("#{@start_date} #{@start_time}") + (@duration.to_f*60*60)
            appointments.each do |a|
                if start_at <= a.end_at - (2*60*60) && start_at >= a.start_at - (1*60*60)
                    errors.add(:start_time)
                    errors.add(:start_date, "An appointment already 
                        exists at #{a.start_at.strftime("%I:%M%p")} of #{a.start_at.strftime("%d/%m/%Y")} 
                        to #{a.end_at.strftime("%I:%M%p")} of #{a.end_at.strftime("%d/%m/%Y")}. 
                        Please select a different date or time.")

                    break

                end
            end

        elsif @start_date.present? && @start_time.present? && duration.present?
            start_at = Time.parse("#{@start_date} #{@start_time}") 
            end_at = Time.parse("#{@start_date} #{@start_time}") + (@duration.to_f*60*60)
            appointments.each do |a|
                if start_at <= a.end_at - (2*60*60) && a.start_at <= end_at 
                    errors.add(:start_time)
                    errors.add(:start_date, "An appointment already 
                        exists at #{a.start_at.strftime("%I:%M%p")} of #{a.start_at.strftime("%d/%m/%Y")} 
                        to #{a.end_at.strftime("%I:%M%p")} of #{a.end_at.strftime("%d/%m/%Y")}. 
                        Please select a different date or time.")
                    break
                end
            end
        end

    end


    def is_date_nil
        if @start_date.blank? && @start_time.blank?
            errors.add(:start_date,  "Start date can't be blank")
            errors.add(:start_time,  "Start time can't be blank")
        end

        if @start_date.blank? && @start_time.present?
            errors.add(:start_date,  "Start date can't be blank")
        end

        if  @start_time.blank? && @start_date.present?
            errors.add(:start_time,  "Start time can't be blank")
        end
    end


    def start_date=(date)
        @start_date = Date.strptime(date, "%d/%m/%Y") if date.present?
    end
    # def save_start_date
    #   @start_date = Date.strptime(@start_date, "%d/%m/%Y") if @start_date.present?
    # end

    # def save_start_date
    #   @start_date = Date.parse(@start_date).strftime("%d/%m/%Y")if @start_date.present?

    # end

    def start_time=(time)
        @start_time = Time.parse(time).strftime("%H:%M:%S") if time.present?
    end

    def duration=(duration)
        @duration = duration if duration.present?
    end

    # def start_date
    #       @start_date.strftime("%d/%m/%Y") if start_at.present?  # || start_at.strftime("%d/%m/%Y") if start_at.present? 
    #   end 

    def start_date
        unless @start_date.blank?
            @start_date.strftime("%d/%m/%Y")
        end
        # start_at.strftime("%d/%m/%Y") if start_at.present? 
    end 

    def start_time
        @start_time || start_at.strftime("%I:%M%p") if start_at.present? 
    end


    # def duration
    #   @duration || 9
    # end

end

执行time_collision_validation后,值字段为空白,我不想要,因为我关注的是UX。即:start_date和start_time字段为空。

当我在HTML源代码中检查输入中的value属性时,该值包含日期字符串。我想知道为什么它没有在现场展示。

有人可以帮我解释一下这是怎么回事吗? &GT;。&LT;

1 个答案:

答案 0 :(得分:0)

validate :time_collision_validation

def time_collision_validation
  appointments = Appointment.all
  if self.start_date.present? && self.start_time.present? && duration.present?
    start_at = Time.parse("#{self.start_date} #{self.start_time}") 
    end_at = Time.parse("#{self.start_date} #{self.start_time}") + (self.duration.to_f.hours)
    appointments.each do |appointment|
      if duration == 0.to_s
        duration_ok = start_at >= appointment.start_at - (1.hours) 
      else
        duration_ok = appointment.start_at <= end_at
      end
      if start_at <= appointment.end_at - (2.hours) && duration_ok
        errors.add(:start_time)
        errors.add(:start_date, "An appointment already 
          exists at #{appointment.start_at.strftime("%I:%M%p")} of #{appointment.start_at.strftime("%d/%m/%Y")} 
          to #{appointment.end_at.strftime("%I:%M%p")} of #{appointment.end_at.strftime("%d/%m/%Y")}. 
          Please select a different date or time.")
        break
      end
    end
  end
end

注意:

  • 您可以不同地引用durationself.duration。为了便于阅读,我总是使用self.duration而不是durationself.duration,因为它使读者清楚您正在谈论当前对象的方法/字段而不是局部变量。我已将当前对象的引用方法/字段的所有实例更改为self.methodname
  • 如果情况如此,你们之间分享了很多重复。我已经重构了这些以避免重复。
  • 2*60*60就像说2.hours,后者更具可读性。
  • start_date和start_time是什么 - 它们是字符串还是日期/时间对象?
  • 而不是在整个数据库中加载每个约会,并循环使用它们,只搜索一个碰撞的其他约会会更有效率。如果你找到一个,那么你可以添加错误。我很想在这里做到这一点,但不清楚你的数据库到底发生了什么。