Rails - фильтр по диапазону дат с 2 моделями - PullRequest
0 голосов
/ 04 апреля 2020

У меня есть две модели: космос и бронирование. Space has_many bookings и Booking имеют два атрибута даты: check_in и check_out.

Учитывая допустимый диапазон дат, я хочу показать все пробелы, доступные в этом диапазоне

Это представление:

        <%= form_tag spaces_path, method: :get do %>
        <%= date_field_tag :query1,
        params[:query1],
        class: "form-control" %>
        <%= date_field_tag :query2,
        params[:query2],
        class: "form-control" %>
        <%= submit_tag "Search", class: "btn" %>
        <% end %>

Это SpaceController:

(...)
def index
    if params[:query1].present? && params[:query2].present?
      query1 = DateTime.parse(params[:query1])
      query2 = DateTime.parse(params[:query2])
      search = query1..query2

      bookings = Booking.all

      # returns the bookings that overlaps with the search
      overlapping_bookings = bookings.select do |booking|
        check_in = booking[:check_in]
        check_out = booking[:check_out]
        period = check_in..check_out
        search.overlaps?(booking.period)
      end

      # returns the spaces_id of the bookings that overlaps
      overlapping_space_ids = overlapping_bookings.select do |overlapping_booking|
        overlapping_booking[:space_id]
      end

      # remove the duplicates
      overlapping_space_ids.uniq!

      # remove the spaces with bookings that overlap with the search
      @spaces = Space.all.reject do |space|
        overlapping_space_ids.include? space[:id]
      end
    else
      @spaces = Space.all
    end
  end
(...)

Я предполагаю, что причина root в том, что я рассматриваю Active Record Query Object как массив хэшей, не уверен, что правильный. Я провел несколько исследований по этому вопросу, но не нашел исчерпывающего ответа.

Ответы [ 2 ]

1 голос
/ 04 апреля 2020

Используя подзапрос SQL (например, в PostgreSQL), вы сделаете это:

sql = <<SQL
SELECT *
FROM spaces
WHERE id in (
  SELECT space_id
    FROM bookings
   WHERE 
    (check_in, check_out) OVERLAPS (:from, :to)
  )
SQL;

Booking.find_by_sql([sql, {from: query1, to: query2})

Надеюсь, это поможет:)

0 голосов
/ 05 апреля 2020

Я бы сначала добавил область к модели Booking:

# in app/models/booking.rb
scope :overlapping, ->(from, to) {
  where(
    "(check_in, check_out) OVERLAPS (?, ?)", from, to
  )
}

, а затем изменил бы весь метод контроллера на:

def index
  @spaces = Space.all

  if params[:query1].present? && params[:query2].present?
    from = DateTime.parse(params[:query1])
    to   = DateTime.parse(params[:query2])

    @space = @space.where.not(
      id: Booking.select(:space_id).overlapping(from, to)
    )
  end
end
...