/ / Cómo validar un rango de números enteros no está incluido en otro rango de números enteros: ruby-on-rails, activerecord

Cómo validar un rango entero no está incluido en otro rango entero - ruby-on-rails, activerecord

Estoy tratando de crear una validación para un período, por lo que un período no contiene otro período dentro de él.

es decir, el período uno es de 25 a 30 y si el período dos se crea para que sea de 20 a 40, debería producirse un error

Estaba tratando de validarlo usando

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

y

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

todo el código está debajo

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

Respuestas

0 para la respuesta № 1

Por lo tanto, el período se superpone si original_start o original_end se incluyen en [start..end] o si [start..end] se incluye en [original_start ..original_end], para el último caso, es suficiente verificar solo un límite.

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))) }

Y sugiero dejar solo una validación, para que el código sea más legible

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