我正在尝试开发像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
您是否有想法以干净的方式实施此重叠检查?
答案 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 })
这将删除places
中bookings
匹配的所有行。 .left_outer_joins
was added in Rails 5.