/ / How to validate an integer range is not included in another integer range - ruby-on-rails, activerecord

Jak sprawdzić poprawność zakresu liczb całkowitych nie jest uwzględniony w innym zakresie liczb całkowitych - ruby-on-rails, activerecord

I am trying to create a validation for a period, so one period does not contain another period inside it.

i.e period one is from 25-30 and if period two is created to be 20-40 it should error

I was trying to validate it by using

def period_cannot_inbetween_and_other_period
return unless period_overlap(start_week, finish_week).any?
errors.add(:start_week, "-", :finish_week, "cannot be in another Period")
end

i

def period_overlap(start_week, finish_week)
self.class.where(":start_week <= start_week AND :finish_week >= finish_week", start_week, finish_week)
end

entire code is below

class Period < ApplicationRecord
has_many :days_till_sellables, dependent: :destroy
belongs_to :organization
validates :name, presence: true
validates :start_week, presence: true
validates :finish_week, presence: true
validates :start_week, inclusion: { in: (1..52), message: "%<value>s must be a valid week number" }
validates :finish_week, inclusion: { in: (1..52), message: "%<value>s must be a valid week number" }

validate :start_week_cannot_overlap_period
validate :finish_week_cannot_overlap_period
validate :start_week_cannot_overlap_period_wrap_around
validate :finish_week_cannot_overlap_period_wrap_around
validate :period_cannot_inbetween_and_other_period

protected

def start_week_cannot_overlap_period
return unless regular_overlap(start_week).any?
errors.add(:start_week, "cannot be in another Period")
end

def finish_week_cannot_overlap_period
return unless regular_overlap(finish_week).any?
errors.add(:finish_week, "cannot be in another Period")
end

def start_week_cannot_include_period
return unless regular_overlap(start_week).any?
errors.add(:start_week, "cannot be in another Period")
end

def start_week_cannot_overlap_period_wrap_around
return unless finish_week > start_week && year_end_overlap(start_week).any?
errors.add(:start_week, "cannot be in another Period")
end

def finish_week_cannot_overlap_period_wrap_around
return unless finish_week > start_week && year_end_overlap(finish_week).any?
errors.add(:finish_week, "cannot be in another Period")
end

def period_cannot_inbetween_and_other_period
return unless period_overlap(start_week, finish_week).any?
errors.add(:start_week, "-", :finish_week, "cannot be in another Period")
end

def regular_overlap(week_of_year)
self.class.where("start_week <= :week_of_year AND finish_week >= :week_of_year", week_of_year: week_of_year)
end

def year_end_overlap(week_of_year)
self.class.where("finish_week < start_week AND (start_week <= :week_of_year OR finish_week >= :week_of_year)",
week_of_year: week_of_year)
end

def period_overlap(start_week, finish_week)
self.class.where(":start_week <= start_week AND :finish_week >= finish_week", start_week, finish_week)
end
end

Odpowiedzi:

0 dla odpowiedzi № 1

So period overlaps if original_start or original_end included in [start..end] or if [start..end] is included to [original_start ..original_end], for last case it is enough to check only one boundary.

scope :ovelapped_periods, ->(start, finish) { where(start_week: (start..finish)).or(end_week: (start..finish)).or(where(arel_table[:start_week].lt(start)).where(arel_table[:end_week].gt(start))) }

And I suggest leaving only one validation, to make the code more readable

validate :overlapping_period
def overlapping_period
if self.class.ovelapped_periods(start_week, end_week).where.not(id: id).any?
errors.add(:start_week, "Period is overlapped other periods")
end
end