2017-11-19 114 views
6

Tạo ứng dụng đặt trước. Làm thế nào tôi có thể kiểm tra hoặc xác nhận ngày ví dụ date_startdate_end có giá trị củaXác định các ngày xung đột khi tạo đường ray

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

tôi sẽ tạo ra một phòng trong đó có những giá trị bắt đầu và ngày kết thúc nhưng nó xung đột với các giá trị khác. Làm cách nào để kiểm tra các ngày xung đột?

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

sử dụng này để xác nhận những ngày ở giữa

Mẫu

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 - chọn ngày

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

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

Sample ngày 26-27 đã đặt/Reserved được cho là nó phải ngăn chặn từ chèn 25 đến 28 vì 26 đến 27 đã được đặt.

+0

Sự cố trong mã của bạn là gì? – Imran

+0

@Imran Tôi muốn có thể thêm xác thực để kiểm tra xung đột giữa các ngày ở trên. Các ngày mẫu từ 26 đến 27 đã được đặt trước/được cho là ứng dụng phải ngăn chặn việc chèn từ 25 đến 28 vì 26 đến 27 đã được đặt trước. – Pat

+0

Bạn đang sử dụng cơ sở dữ liệu nào (nếu bạn muốn một giải pháp dựa trên SQL)? –

Trả lời

3

mẫu:

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 

Đây là rails console log sau khi tôi đã cố gắng để tạo (24 tháng mười một - 27 tháng 11) và (25 Tháng mười một - 27 tháng 11) khi có (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 
=> # 

Có những hạn chế như mong đợi.

+0

Không còn chèn ngày tạo đặt chỗ cho 25-26 và người dùng cũ sẽ tạo một đặt chỗ khác cho ngày 24-27 tháng 11. Đây là lỗi vì 25-26 đã được đặt trước, cách có thể Tôi kiểm tra hoặc xác nhận ngày để nó không xung đột với các ngày khác? – Pat

+0

Tôi đã thêm tất cả các bước tôi đã thực hiện –

2
  • Sẽ có nhiều ngày trên bảng đặt phòng của bạn. ví dụ:

    • đặt phòng một: 7.days.from_now ~ 6.days.from_now
    • đặt phòng hai: 3.days.from_now ~ 1.days.from_now
  • Có nghĩa là bạn phải nhận ra ngày dự trữ theo từng phạm vi.

    • ban đầu: 1 ~ 3, 6 ~ 7
  • tôi đã sử dụng một băm để ngày chỉ số dành riêng, như thế này:

    • không ngày có sẵn (từ bây giờ): 1, 2, 3, 6, 7
    • cũng có thể tạo chỉ mục hiệu quả được thu hẹp bằng cách tìm kiếm (hoặc phạm vi) chỉ ngày date_start và date_end hoặc đặt chỗ đang hoạt động

mẫu:

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

xác nhận của bạn không hoạt động vì bạn đang kiểm tra rằng số ngày dự trữ mới là giữa ngày đặt đã tồn tại trong cơ sở dữ liệu. Trong trường hợp cụ thể mà bạn đã đề cập, bạn cần phải kiểm tra ngày đặt phòng hiện có là giữa các ngày trong ngày đặt phòng mới.

Ví dụ đề cập trong câu hỏi để tham khảo:

đặt phòng

Đã tồn tại trong cơ sở dữ liệu

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

đặt phòng mới:

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

Bạn cần phải kiểm tra sự các trường hợp sau:

Notation:

  • R1 là phòng đã tồn tại trong cơ sở dữ liệu
  • R2 được người dùng đặt phòng mới đang cố gắng thêm.
  • | là đại diện cho ngày bắt đầu và ngày kết thúc

Trường hợp1

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

khi R1 bắt đầu và kết thúc trước khi R2

Trường hợp2

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

khi R2 bắt đầu và kết thúc trước khi R1

Case3

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

Khi R2 chứa R1. (Vụ này bạn đã đề cập trong câu hỏi của bạn)

Case4

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

Khi R1 chứa R2. (Đây là trường hợp duy nhất bạn có trong phạm vi chồng chéo của mình)

Tuyên bố từ chối trách nhiệm: Phạm vi dưới đây chưa được kiểm tra và có thể có một số vấn đề. (Bạn có thể dễ dàng viết truy vấn SQL bằng cách bao gồm tất cả các trường hợp trên)

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 
Các vấn đề liên quan