0

我正在尝试开发类似 Rails 的 Airbnb 应用程序,但由于重叠检查系统而被阻止;当我们检查这个地方是否已经被预订时。这里的困难是我需要检查日期是否重叠以及时间。因为在我的项目中,您只有在需要时才能租用几个小时的地方。

架构:

  create_table "bookings", force: :cascade do |t|
    t.integer "user_id"
    t.integer "place_id"
    t.datetime "start_time"
    t.datetime "end_time"
    t.integer "price"
    t.integer "total"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["place_id"], name: "index_bookings_on_place_id"
    t.index ["user_id"], name: "index_bookings_on_user_id"
  end

  create_table "places", force: :cascade do |t|
    t.integer "user_id"
    t.string "name"
    t.integer "price"
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["user_id"], name: "index_places_on_user_id"
  end

您是否有想法以干净的方式实施这种重叠检查?

4

1 回答 1

2

你想要的是一个 BETWEEN 查询:

booked = Place.joins(:bookings)
  .where('? BETWEEN bookings.start_time AND bookings.end_time OR 
          ? BETWEEN bookings.start_time AND bookings.end_time', 
          starts_at, ends_at)

您可以创建一个范围方法以避免重复:

class Booking
  def self.between(starts_at, ends_at)
    where(
     '? BETWEEN bookings.start_time AND bookings.end_time OR ? BETWEEN bookings.start_time AND bookings.end_time', 
     starts_at, ends_at
    )
  end
end

由于.joins创建了左内连接,因此只会返回连接表中匹配的行。要获得逆向,最简单的方法是在两个查询中进行:

available = Place.where.not(id: booked)

您还可以使用左外连接:

available = Place.left_outer_joins(:bookings)
     .where(bookings: Booking.between(starts_at, ends_at))
     .where(bookings: { id: nil })

这将从 中删除任何places匹配的行bookings.left_outer_joins在 Rails 5 中添加。

于 2017-12-15T18:24:07.230 回答