【问题标题】:Rails - filter by date range with 2 modelsRails - 使用 2 个模型按日期范围过滤
【发布时间】:2020-04-04 17:55:27
【问题描述】:

我有两种模式:空间和预订。 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 %>

这是空间控制器:

(...)
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


    【解决方案1】:

    使用 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})
    

    希望有帮助:)

    【讨论】:

      【解决方案2】:

      我会先为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
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-29
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-05-25
        • 2018-06-19
        相关资源
        最近更新 更多