如何检查Rails中的时间范围是否重叠? (Airbnb喜欢申请)

时间:2017-12-15 17:43:21

标签: ruby-on-rails ruby overlapping-matches

我正在尝试开发像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

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

1 个答案:

答案 0 :(得分: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 })

这将删除placesbookings匹配的所有行。 .left_outer_joins was added in Rails 5.