Rails-使用2个模型按日期范围过滤

问题描述 投票:1回答:3

我有两种模式:空间和预订。 has_many个预订空间,而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
(...)

我认为是我的问题的根本原因是我将Active Record Query Object视为哈希数组,不确定是否正确。我对此进行了一些研究,但没有找到详尽的答案。

ruby-on-rails ruby rails-activerecord
3个回答
0
投票

[您可以使用两个表之间的关系,并从每次预订中获得入住空间,其中入住日期比给定日期短,而check_out也比给定日期大:

Space.joins(:bookings)
     .where('bookings.check_in <= ? AND bookings.check_out >= ?', 
            params[:query1], params[:query2])

0
投票

使用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
投票

我首先将范围添加到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
© www.soinside.com 2019 - 2024. All rights reserved.