我有两种模式:空间和预订。 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
视为哈希数组,不确定是否正确。我对此进行了一些研究,但没有找到详尽的答案。
[您可以使用两个表之间的关系,并从每次预订中获得入住空间,其中入住日期比给定日期短,而check_out也比给定日期大:
Space.joins(:bookings)
.where('bookings.check_in <= ? AND bookings.check_out >= ?',
params[:query1], params[:query2])
使用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})
希望有所帮助:)
我首先将范围添加到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