首页 > 解决方案 > rails 模型范围没有选择好的查询

问题描述

我想选择可预订的优惠,我将到达和离开日期搜索参数与范围内每个优惠的预订确认日期进行比较。

提供型号:

has_many :bookings

scope :booking_available, -> (arrival_date, departure_date) {
  includes(:bookings)
    .references(:bookings)
    .where.not(
      'bookings.arrival_date <= ? AND
      bookings.departure_date >= ? AND
      bookings.status != ?',
      arrival_date,
      departure_date,
      0
    )
}

预订型号:

belongs_to :offer

并在控制器的搜索功能中调用它。

if offer_params[:arrival_date].present? && offer_params[:departure_date].present?
  @offers = @offers.booking_available(
    offer_params[:arrival_date],
    offer_params[:departure_date]
  )
end

但结果只给我提供不可用的优惠,我认为.not在我的查询中不起作用,我不知道如何修复它。

标签: ruby-on-railsrubypostgresql

解决方案


考虑到复杂性,我认为您需要将其分开,以便您可以单独测试各个部分。

您将业务逻辑描述为“在……(条件)处没有预订的报价”。

这建议一个查询,如:

Offer.joins("left outer join bookings on bookings.offer_id = offers.id").
      select("offers.*, count(bookings.id)").
      group("offers.id").
      having("count(bookings.id) = 0")

# yeah, I didn't write it as a scope, b/c it's a bit more readable
# you can make it a scope if you wish

写一个测试并确保这会给你正确的结果。它尚未选择“可用预订”。所以现在我们添加预订可用标准:

available_bookings = Booking.available(ar_date, dep_date).to_sql

joins = "left outer join (#{available_bookings}) as available_bookings on available_bookings.offer_id = offers.id"

Offer.joins(joins).
      select("offers.*, count(available_bookings.id)").
      group("offers.id").
      having("count(available_bookings.id) = 0")

通过将预订可用性标准委托给 Booking 模型,我们可以单独对其进行测试。让我看看我是否正确理解了您所说的可用预订的含义:

# booking.rb

scope :available, ->(arrival_date, departure_date){ 
       outside_of(arrival_date, departure_date).not_pending(arrival_date, departure_date) 
}

scope :outside_of, ->(arrival_date, departure_date){ 
       where("arrival_date <= ? and departure_date >= ?", arrival_date, departure_date) 
}

scope :not_pending, ->(arrival_date, departure_date){ 
       where.not("arrival_date >= ? and departure_date <= ? and status != ?",arrival_date, departure_date, 0)
}

这为您提供了三个可以单独测试的 Booking 范围。

测试组件在这里至关重要,以确保每个组件都按预期工作。

在风格上,将预订范围保留在 Booking 模型中,而不是在 Offer 模型中是一种很好的做法(甚至可能是最佳做法)。可测试性是原因之一。

让我们知道这是怎么回事。


推荐阅读