How to validate overlapping times in Rails

前端 未结 4 1310
渐次进展
渐次进展 2021-01-20 07:08

I have an Event model that has form time and to time in my schedule app and I want to validate the overlapping time before saving.

相关标签:
4条回答
  • Well, if you need a server side validation, you could implement some custom validators in your model class:

    validate :cannot_overlap_another_event
    

    Next you need to code this method yourself:

    def cannot_overlap_another_event
      range = Range.new from, to
      overlaps = Appointment.exclude_self(id).in_range(range)
      overlap_error unless overlaps.empty?
    end
    

    Explaining what this code do, you create a Range object with your from and to dates. Then it uses the helper scopes to exclude the Event itself and check to see if there's an event in this range.

    scope :in_range, -> range {
      where('(from BETWEEN ? AND ?)', range.first, range.last)
    }
    scope :exclude_self, -> id { where.not(id: id) }
    

    The overlap_error is a method that populates the model's error hash to display on screen:

    def overlap_error
      errors.add(:overlap_error, 'There is already an event scheduled in this hour!')
    end
    
    0 讨论(0)
  • 2021-01-20 07:23

    I had the same problem for a project, my solution is to include a validation method inside the model, so I have a model for vacation periods taken and I must add periods (lapses) taking care that those lapses are not overlapping; Suppose you have a collection of lapses taken (active_permits) and you just got a new lapse from your form (lapse) then there are only two fundamental rules that will determine if the two periods are overlapping: lapse[:end] must be smaller (that is occurs earlier) than active_permit[:start] OR lapse[:start] must be greater (occurs later) than active_permit[:end], so UNLESS one of these rules are met, the two periods overlap. Code must be something like this:

    def lapse_validation(lapse)
      error = 0
      @active_permits.each do |active_permit|
        unless (lapse[:end] < active_permit[:start] || lapse[:start] > active_permit[:end])
          error = 1
          errors.add(:new_permit, ": The dates you entered overlapp an existing leave period")
        end
      end
      return error
    end
    

    You can find a more detailed discussion on overlapping periods here: https://www.soliantconsulting.com/blog/determining-two-date-ranges-overlap/

    0 讨论(0)
  • 2021-01-20 07:28

    In your EventsController#Create & EventsController#Update methods check for new time in between the old times like :

    events = Event.where(:departure_date => event_params[:departure_date])
    events.each do |event|
     if event_params[:to].between?(event.to, event.from) || event_params[:from].between?(event.to, event.from)
      flash[:error] = "Current Slot Time is already taken!"
      redirect_to :back
      return
     end
    end
    
    0 讨论(0)
  • 2021-01-20 07:35

    Take a look at this https://makandracards.com/makandra/984-test-if-two-date-ranges-overlap-in-ruby-or-rails. The key is to define one scope to chek for overlapping siblings. Somthing like this:

    # Return a scope for all interval overlapping the given interval, including the given interval itself
      named_scope :overlapping, lambda { |interval| {
        :conditions => ["id <> ? AND (DATEDIFF(start_date, ?) * DATEDIFF(?, end_date)) >= 0", interval.id, interval.end_date, interval.start_date]
      }}
    

    Also you can check this gem: https://github.com/robinbortlik/validates_overlap I think it can help.

    0 讨论(0)
提交回复
热议问题