2017-11-19 132 views
6

Bir rezervasyon uygulaması oluşturma. Ben kontrol etmek veya örneğin date_start ve date_end tarihini doğrulamak nasılRaylarda oluştururken çakışan tarihleri ​​belirleme

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

Bunları başlayan ve bitiş tarihi değerlere sahip başka bir rezervasyon yaratacak bir değere sahiptir fakat diğer değerlerle çelişmektedir. Çakışan tarihleri ​​nasıl kontrol edebilirim?

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 

Modeli

arasındaki View tarihleri ​​doğrulamak için bu Kullanılan

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

-

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

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

Numune zaten/rezerve sözde saklıdır 26 ila 27 büyük tarihi seçerek 26 ila 27 önceden rezerve edildiği için 25 ila 28 eklemesi engellenmelidir.

+0

(Kolayca yukarıdaki tüm olguları da kapsayarak, bir SQL sorgusu yazabilir)? – Imran

+0

@Imran Yukarıdaki tarihler arasındaki çakışmaları kontrol etmek için bir doğrulama ekleyebilmek istiyorum. 26'dan 27'ye kadar olan örnek tarihler önceden rezervasyon yaptırılmış/rezerve edilmiştir, söz gelimi uygulama 25 ila 28'i eklemekten sakınmalıdır, çünkü 26'dan 27'ye kadar olan rezervasyonlar zaten ayrılmıştır. – Pat

+0

Hangi veritabanını kullanıyorsunuz (SQL tabanlı bir çözüm istiyorsanız)? –

cevap

3

Modeli:

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 

Şema: Ben ortaya çıkmasına çaba Burada

 
    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 

rails console log (24 Kasım - 27 Kasım) ve (25 Kasım - 27 Kasım) vardı (25 nov - 26 nov)

 
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 
=> # 

Beklendiği gibi geri almalar vardır.

+0

Hala 25-26 nov için bir rezervasyon oluşturulduğu tarihi ekler ve aynı kullanıcı şimdi 24-27 nov için başka bir rezervasyon yaratacaktır. Tarihi kontrol edip onaylıyorum, bu yüzden diğer tarihlerle çakışmıyor mu? – Pat

+0

Yaptığım tüm adımları ekledim –

2
  • Rezervasyonlarınızda birçok tarih olacak.

    • rezervasyon biri: 7.days.from_now ~ 6.days.from_now
    • rezervasyon iki: 3.days.from_now ~
  • seni kastediyor 1.days.from_now örneğin Ayrılmış tarihi her bir aralıkta tanımak zorundadır.

    • aslen: (bundan)

      • mevcut değil tarih: 1 ~ 3, 6 ~ 7
    • böyle, endeks saklıdır tarihlerine bir karma kullanılan 1, 2, 3, 6, aynı zamanda 7

    • , sen verimli aramalar yapan (veya kapsama alınması) tarafından daralmış indeksi sadece hedef DATE_START ve DATE_END veya aktif çekinceleri oluşturabilir

Model:

Yeni rezervasyon tarihleri ​​veritabanında zaten var olan rezervasyonları tarihleri ​​arasında olduğunu kontrol ediyoruz, çünkü doğrulama çalışmıyor
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

. Bahsettiğiniz özel durumda, mevcut rezervasyon tarihlerini kontrol etmeniz gereken tarihler, yeni rezervasyon tarihlerindeki tarihler arasındadır. başvuru için söz konusu belirtilen

Örnek: veritabanında

Zaten mevcut rezervasyon

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

Yeni rezervasyon:

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

Sen için kontrol edilmesi gereken aşağıdaki durumlarda:

Notasyon:

  • R1 yeni rezervasyon kullanıcı eklemek için çalışıyor veritabanında zaten
  • R2 mevcut rezervasyon olmasıdır.
  • | başlangıç ​​ve bitiş tarihi

Durum 1

temsil etmektedir
|------R1------| 
    ____|------R2------| 

R1 başlar ve biter R2

Durum 2

önce
______|------R1------| 
    |------R2------|______ 

R2 başlar ve biter önce R1,

Case3

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

R2, R1 ihtiva eder. R1 R2 içerdiğinde

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

Case4 (vaka senin soru belirtmiştik). (Bu, örtüşen kapsamının üstündeki tek durumdur)

Yasal Uyarı: Aşağıdaki kapsamı test edilmemiştir ve bazı sorunlar olabilir. Kodunuzdaki sorunu nedir

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