2017-11-19 165 views
6

Tworzenie aplikacji rezerwacji. Jak mogę sprawdzić, czy zatwierdzić datę przykład date_start i date_end ma wartośćIdentyfikacja konfliktów dat na tworzenie w szynach

date_start date_end 
26-11-2017 27-11-2017 

będę tworzyć kolejną rezerwację, która ma te wartości rozpoczęcia i data zakończenia, ale to sprzeczne z innymi wartościami. Jak mogę sprawdzić sprzeczne daty?

date_start date_end 
25-11-2017 28-11-2017 

Używane to do sprawdzania poprawności daty w między

model

validate :no_reservation_overlap 

scope :overlapping, ->(period_start, period_end) do 
    where "((date_start <= ?) and (date_end >= ?))", period_end, period_start 
end 

private 

def no_reservation_overlap 
    if (Reservation.overlapping(date_start, date_end).any?) 
    errors.add(:date_end, 'it overlaps another reservation') 
    end 
end 

View - Wybierając datę

<%= f.label :'date_start:' %> 
<%= f.date_field :date_start %> 

<%= f.label :'date_end:' %> 
<%= f.date_field :date_end %> 

Próbka pochodzi od 26 do 27 są już zarezerwowane/zastrzeżone rzekomo musi uniemożliwić wstawienie 25 do 28, ponieważ 26 do 27 są już zarezerwowane.

+0

Na czym polega problem w twoim kodzie? – Imran

+0

@Imran Chcę móc dodać sprawdzanie poprawności w celu sprawdzenia konfliktów między powyższymi datami. Przykładowe daty od 26 do 27 są już zarezerwowane/zarezerwowane, podobno aplikacja musi zapobiegać wstawianiu od 25 do 28, ponieważ 26 do 27 jest już zarezerwowanych. – Pat

+0

Jaką bazę danych używasz (jeśli potrzebujesz rozwiązania opartego na języku SQL)? –

Odpowiedz

3

Model:

class Reservation < ApplicationRecord 
    validate :overlapping 
    private 
    def overlapping 
    if Reservation.where('? < date_end and ? > date_start', self.date_start, self.date_end).any? 
     errors.add(:date_end, 'it overlaps another') 
    end 
end 

Schema:

 
    create_table "reservations", force: :cascade do |t| 
     t.date  "date_start" 
     t.date  "date_end" 
     t.datetime "created_at", null: false 
     t.datetime "updated_at", null: false 
    end 

Oto rails console dziennika po starałem się tworzyć (24 listopada - 27 listopada) i (25 listopada - 27 listopada), gdy był (25 nov - 26 now)

 
irb(main):003:0> Reservation.create date_start: Date.parse('25-11-2017'), date_end: Date.parse('26-11-2017') 
    (0.2ms) BEGIN 
    (0.6ms) SELECT COUNT(*) FROM "reservations" WHERE ('2017-11-25' date_start) 
    SQL (0.6ms) INSERT INTO "reservations" ("date_start", "date_end", "created_at", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id" [["date_start", "2017-11-25"], ["date_end", "2017-11-26"], ["created_at", "2017-11-21 13:23:05.192276"], ["updated_at", "2017-11-21 13:23:05.192276"]] 
    (10.7ms) COMMIT 
=> # 
irb(main):004:0> Reservation.create date_start: Date.parse('24-11-2017'), date_end: Date.parse('27-11-2017') 
    (0.1ms) BEGIN 
    (0.2ms) SELECT COUNT(*) FROM "reservations" WHERE ('2017-11-24' date_start) 
    (0.2ms) ROLLBACK 
=> # 
irb(main):005:0> Reservation.create date_start: Date.parse('25-11-2017'), date_end: Date.parse('26-11-2017') 
    (0.1ms) BEGIN 
    (0.3ms) SELECT COUNT(*) FROM "reservations" WHERE ('2017-11-25' date_start) 
    (0.1ms) ROLLBACK 
=> # 

Istnieją wycofania zgodnie z oczekiwaniami.

+0

Wciąż nie wstawia daty utworzenia rezerwacji dla nowszych 25-26 i ten sam użytkownik utworzy teraz kolejną rezerwację na 24-27 nov, to jest podobno błąd, ponieważ nowsza 25-26 jest już zarezerwowana, jak może Sprawdzam lub sprawdzam datę, aby nie kolidowała z innymi datami? – Pat

+0

Dodałem wszystkie kroki, które zrobiłem –

2
  • Będzie wiele dat na stole rezerwacji. na przykład:

    • rezerwacji jeden: 7.days.from_now ~ 6.days.from_now
    • rezerwacja dwa: 3.days.from_now ~ 1.days.from_now
  • co oznacza, że muszą rozpoznać zarezerwowaną datę dla każdego zakresu.

    • pierwotnie: 1 ~ 3, 6 ~ 7
  • użyłem skrótu do indeksu zastrzeżone terminach, tak:

      nie
    • wolne terminy (od teraz): 1, 2, 3, 6, 7
    • możesz także utworzyć efektywny indeks zawężony przez wyszukiwanie (lub zakres) tylko docelowy date_start i date_end lub aktywne rezerwacje

Model:

class Reservation < ApplicationRecord 
    validate :exclusive_reservation? 

    def exclusive_reservation? 
     result = true 
     reserved = {} 

     Reservation.pluck(:date_start, :date_end).each do |date_range| 
      (date_range.first..date_range.second).each do |date| 
       reserved[date] = true 
      end 
     end 

     if reserved.has_key? self.date_start 
      errors.add(:date_start, 'it overlaps another reservation') 
      result = false 
     end 

     if reserved.has_key? self.date_end 
      errors.add(:date_end, 'it overlaps another reservation') 
      result = false 
     end 

     result 
    end 
end 
2

Twój walidacja nie działa, ponieważ jesteś sprawdzając, że nowe terminy rezerwacji są między rezerwacji terminów już istniejących w bazie danych. W konkretnym przypadku, o którym wspomniałeś, musisz sprawdzić obecne daty rezerwacji między datami w nowych datach rezerwacji.

Przykład wspomniano w pytaniu dla odniesienia:

już istniejącą już rezerwację w bazie

date_start date_end 
26-11-2017 27-11-2017 

New rezerwacja:

date_start date_end 
25-11-2017 28-11-2017 

Trzeba sprawdzić dla następujące przypadki:

Notation:

  • R1 jest rezerwacja już istniejących w bazie
  • R2 jest nowy użytkownik rezerwacja próbuje dodać.
  • | reprezentuje datę uruchomienia, data zakończenia

CASE1

|------R1------| 
    ____|------R2------| 

gdy R1 zaczyna się i kończy się przed R2

Przypadek 2

______|------R1------| 
    |------R2------|______ 

gdy R2 zaczyna się i kończy się przed R1

Case3

___|------R1------|___ 
    |---------R2---------| 

Gdy R2 zawiera R1. (Sprawa już wspomniano w pytaniu)

Case4

 |---------R1---------| 
    __|------R2------|___ 

Gdy R1 zawiera R2. (Jest to jedyny przypadek objęty zasięgiem pokrywający zakres)

Nota prawna: Poniższy zakres nie jest testowany i może mieć pewne problemy. (Możesz łatwo napisać zapytanie SQL, opisując wszystkie powyższe przypadki)

scope :overlapping, ->(period_start, period_end) do 
      where(
       "(:period_start <= date_start AND :period_end < date_end AND :period_start > period_end) OR 
       (:period_start >= date_start AND :period_end > date_end AND :period_start < date_end) OR 
       (:period_start < date_start AND :period_end >= date_end) OR 
       (:period_start >= date_start AND :period_end <= date_end)",period_start: period_start, period_end: period_end) 
     end