Ruby на рельсах лямбда с левым соединением и условием

#ruby-on-rails #ruby #lambda

Вопрос:

В номере есть много бронирований

Бронирование принадлежит номеру

У меня есть этот код, и он отлично работает:

 available_rooms = Room.select {|room| room.bookings.where("day = ?", date).count < 3 || room.bookings.empty?}
 

но мне интересно, можно ли переписать его как лямбду с левым соединением

 scope :available, lambda {|date| joins('LEFT OUTER JOIN bookings on bookings.room_id = rooms.id').......
 

Я попробовал это, но получил обратно только номера по крайней мере С одним Бронированием, поэтому полностью пустые номера БЕЗ каких-либо бронирований были исключены:

   def self.available(date)
    # You can use `Arel.star` instead of `:id` on postgres.
    b = Booking.arel_table[:id]
    group(:id)
      .left_joins(:bookings)
      .where(bookings: { day: date })
      .having(b.count.lt(3)) # COUNT(bookings.id) < 3
  end
 

Комментарии:

1. Спасибо! Но в этом случае я получу только те номера, которые забронированы на эту дату. Что мне нужно — все номера, которые вообще не забронированы на эту дату номера, которые забронированы на эту дату, но общая сумма этих бронирований составляет

2. Может быть, вы могли бы добавить в свой запрос предложение «иметь» и «группа»? .having("COUNT(date) < 3").group(:id)

Ответ №1:

ОБНОВЛЕНИЕ Для удовлетворения требования вам действительно понадобится сложное соединение, пожалуйста, попробуйте вместо этого следующее

 class Room < ApplicationRecord
  def self.available(date)
    b = Booking.arel_table
    join_statement = Arel::Nodes::OuterJoin.new(b,
      Arel::Nodes::On.new(
        arel_table[:id].eq(b[:room_id])
          .and(b[:day].eq(Arel::Nodes.build_quoted(date)))
    ))
    group(:id)
      .joins(join_statement)
      .having(b[:id].count.lt(3))
  end
end
 

Здесь нам остается присоединиться bookings в зависимости от отношения к комнате и запрошенной даты. Теперь, если номер не забронирован на эту дату или у него менее 3 бронирований на эту дату, он должен появиться в соответствии с запросом.

Комментарии:

1. Спасибо за помощь! @engineersmnky Это почти работает, но в данном случае у меня есть: — все свободные номера (без бронирования вообще) — все номера с бронированием на НЕКОТОРУЮ дату с общей суммой

2. @Ирина Я вижу. Обновлено соответственно с 2-м условием присоединения.

3. Еще раз спасибо вам! Я получаю эту ошибку, на самом деле не могу найти проблему… «SQLite3::Исключение SQLException: неоднозначное имя столбца: main.rooms.id»

4. @Ирина Я понятия не имею, как это можно считать двусмысленным, мне кажется, это полностью соответствует требованиям. Также я бы настоятельно рекомендовал использовать готовую к работе базу данных, например PostgreSQL, MySQL, MariaDB, MSSQL и т.д. У SQLite много причуд, с большинством из которых я недостаточно знаком, чтобы действительно быть в состоянии оказать адекватную помощь.