更快的数据库WHERE for Rails可用性日历

我正在建立一个Ruby on Rails宿舍床预订系统,我正在寻找一种更好的方式来加载我的可用性日历。 下面的代码非常适合显示床的可用性(参见附图),但我觉得多个WHERE数据库调用在服务器上过于繁琐,必须有更快的方法来处理数据。

楷模:

user.rb

bed.rb(user_id,name)

guest.rb(user_id,姓名,电话,地址,电子邮件)

reservation.rb(user_id,bed_id,guest_id,date)

用户是宿舍业主。 他们创造了与他们的生意一样多的床并给他们起了一个名字(Bed#1,Bed#2,Twin-Attic,Master-2nd Floor等)。

每个用户都有很多客人,这些人是在特定日期在宿舍睡觉的人。

使用simple_calendar gem,我获得当前月份的所有预订并处理它们以显示每周视图。

排序逻辑:

步骤1.在一周的第一天通过current_user的床进行迭代。(simple_calendar提供每天的预订)

步骤2.如果床有当天的预订(!=无),请提供床名和预订的客人姓名。

步骤3.如果床没有预订,请将床名和“空”。

步骤4.完成一周的第一天后,转到第二天并重复。(simple_calendar处理此事)

正如我所说的,下面的代码有效,但是当用户有50张床位时,每天会拨打50个WHERE电话,因此对于7天日历会有350个(如果需要找到客人的姓名,则会有更多)。

如果您需要更多信息或解释,请与我们联系。 谢谢!

= week_calendar events: @monthly_reservations, attribute: :date do |date, appts| - current_user.beds.each do |bed| - if bed.reservations.where(date: date).first != nil - guest_name = bed.reservations.where(date: date).first.guest.abbreviated_name %p{style: "border: 1px solid black; padding: 5px; font-size: 10px;"} = "#{bed.name}: #{guest_name}" - else %p{style: "border: 1px solid black; padding: 5px; font-size: 10px;"} = "#{bed.name}: Empty" 

CURRENT Rails宿舍床预订系统

编辑:理想的日历布局如下图所示:

IDEAL Rails床预订系统

然而,问题是使床名与正确的床位保持一致。 如果5月2日只有2个预订,1床和4床,代码不知道在入住Bed 4的预约之前留下两个EMPTYS。 合理?

编辑#2:

@DavidAldridge,像这样:

像这样的东西?

reservs = {"[2017-05-01, bed_1]" => "guest_23", "[2017-05-01, bed_2]" => "empty"}

编辑3这是在加载只有5张床的宿舍时的日志。

 Bed Load (0.3ms) SELECT "beds".* FROM "beds" WHERE "beds"."user_id" = $1 [["user_id", 1]] Reservations Load (0.2ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 1], ["date", "2017-07-02"]] Reservations Load (0.2ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 2], ["date", "2017-07-02"]] Reservations Load (0.2ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 3], ["date", "2017-07-02"]] Reservations Load (0.2ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 4], ["date", "2017-07-02"]] Reservations Load (0.2ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 5], ["date", "2017-07-02"]] Reservations Load (0.2ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 1], ["date", "2017-07-03"]] Reservations Load (0.2ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 2], ["date", "2017-07-03"]] Reservations Load (0.2ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 3], ["date", "2017-07-03"]] Reservations Load (0.2ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 4], ["date", "2017-07-03"]] Reservations Load (0.2ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 5], ["date", "2017-07-03"]] Reservations Load (0.2ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 1], ["date", "2017-07-04"]] Reservations Load (0.2ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 2], ["date", "2017-07-04"]] Reservations Load (0.2ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 3], ["date", "2017-07-04"]] Reservations Load (0.2ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 4], ["date", "2017-07-04"]] Reservations Load (0.1ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 5], ["date", "2017-07-04"]] Reservations Load (0.2ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 1], ["date", "2017-07-05"]] Reservations Load (0.2ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 2], ["date", "2017-07-05"]] Reservations Load (0.2ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 3], ["date", "2017-07-05"]] Reservations Load (0.2ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 4], ["date", "2017-07-05"]] Reservations Load (0.2ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 5], ["date", "2017-07-05"]] Reservations Load (0.2ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 1], ["date", "2017-07-06"]] Reservations Load (0.2ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 2], ["date", "2017-07-06"]] Reservations Load (0.1ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 3], ["date", "2017-07-06"]] Reservations Load (0.1ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 4], ["date", "2017-07-06"]] Reservations Load (0.3ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 5], ["date", "2017-07-06"]] Reservations Load (0.2ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 1], ["date", "2017-07-07"]] Reservations Load (0.2ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 2], ["date", "2017-07-07"]] Reservations Load (0.2ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 3], ["date", "2017-07-07"]] Reservations Load (0.2ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 4], ["date", "2017-07-07"]] Reservations Load (0.1ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 5], ["date", "2017-07-07"]] Reservations Load (0.2ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 1], ["date", "2017-07-08"]] Reservations Load (0.6ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 2], ["date", "2017-07-08"]] Reservations Load (0.3ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 3], ["date", "2017-07-08"]] Reservations Load (0.3ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 4], ["date", "2017-07-08"]] Reservations Load (0.3ms) SELECT "reservations".* FROM "reservations" WHERE "reservations"."bed_id" = $1 AND "reservations"."date" = $2 ORDER BY "reservations"."id" ASC LIMIT 1 [["bed_id", 5], ["date", "2017-07-08"]] 

编辑4在@DavidAldridge建议之后,我在控制器中创建了一个哈希并将其传递到我的视图中。 结果是STELLAR!

控制器代码:

 @reservations = {} @monthly_reservations.each do |x| @reservations[[x.date,x.bed_id]] = x.guest.try(:name) end 

和视图代码:

 = week_calendar events: @monthly_reservations, attribute: :date do |date, appts| - current_user.beds.each do |bed| - if @reservations[[date, bed.id]] != nil %p{style: "border: 1px solid black; padding: 5px; font-size: 10px;"} = "#{bed.name}: #{@reservations[[date, kennel.id]]}" - else %p{style: "border: 1px solid black; padding: 5px; font-size: 10px;"} = "#{bed.name}:" 

Robbie所描述的是批量捕获数据以在第二遍中呈现它。 你可以这样做:

 @reservations = Reservations.where(bed_id: [ ... ], date: (from..to)).group_by do |r| [r.bed_id, r.date] end 

这将返回一个单一结构,该结构应该包含所有预留,并且可以使用bed_id和日期轻松索引。 如有必要,您可以将其转换为双层结构,但通常不会。

迭代时:

 - current_user.beds.each do |bed| - reservation = @reservations[[bed.id,date]] - if reservation # ... 

当你处理复杂的相互依赖关系时,这种选择性但积极地加载记录的做法通常很有效,这些依赖关系不能用加载链中的includes(..)元素轻易表达。

另外,请记住在Ruby中只有两个逻辑错误的东西:literal falsenil 。 其他所有内容都评估为逻辑真,包括0,空字符串,数组和散列。 因此,比较!= nil几乎总是无关紧要,特别是如果你做双重否定,比如unless (x != nil)

如果您希望能够针对数据库解决许多任意日期+床对,您可以制作某种类型的预订密钥,这是日期和bed_id的组合,那么扫描这些就更容易了。 你可以做一个WHERE booking_token IN (...)并让它全部编入索引, WHERE booking_token IN (...) ,简洁。 虽然要正确地进行,但需要一些提前计划。 YYYY-MM-DD-bed_id可以作为第一关。

对于您的视图代码,我会尝试:

 = week_calendar events: @monthly_reservations, attribute: :date do |date, appts| - current_user.beds.each do |bed| %p{style: "border: 1px solid black; padding: 5px; font-size: 10px;"} = [bed.name, @reservations[[date, bed.id]]].compact.join(":")