0

我有 2 个模型:

DeliverySlot has_many :orders Order belongs_to :delivery_slot

Delivery Slots 对它们可以容纳的订单数量有限制。我想创建一个范围来提供所有可用的交付槽。可用的交货时段是尚未达到其关联订单限制的交货时段。

我的尝试看起来像:

scope :available, where("limit > ?", order.count).joins(:orders)

order.count 是上面的伪代码。

4

3 回答 3

2

要做到这一点,就像你有设置一样,你需要使用orders.count而不是order.count因为你指的是关联。这将提示 ActiveRecord 组装一个看起来像SELECT COUNT(*) FROM orders WHERE delivery_slot_id = 1.

Rails 实际上足够聪明,可以在您where适当地传递它时将其用作条件中的子查询,例如 la where('limit > ', orders.count)。但正如您可能看到的,如果它是预编译的,这将不起作用,因为查询在条件中使用了显式 ID。

相反,您需要计算条件不明确的订单,然后将其用作子查询:where('limit > ?', Order.where(delivery_slot_id: 'delivery_slots.id').count)。如果您尝试单独运行订单计数的查询,它将失败delivery_slots,但因为它在此处的子查询中,您应该一帆风顺。

我想提出另一种完全这样做的方法,使用计数器缓存:

class AddCounterCacheToDeliverySlots < ActiveRecord::Migration
  class DeliverySlot < ActiveRecord::Base; end
  def change
    add_column :delivery_slots, :orders_count, :integer, default: 0
    add_index :delivery_slots, [:orders_count, :limit]

    DeliverySlot.reset_column_information
    DeliverySlot.find_each do |delivery_slot|
      DeliverySlot.update_counters delivery_slot.id, orders_count: delivery_slot.orders.count
    end
  end
end

class Order < ActiveRecord::Base
  belongs_to :delivery_slot, counter_cache: true
end

class DeliverySlot < ActiveRecord::Base
  has_many orders
  scope :available, where('orders_count < limit')
end

Rails 会自动递增和递减orders_counteach 的列DeliverySlot,并且因为它是索引的,所以查询起来快得离谱。

于 2013-05-29T22:59:44.420 回答
0

所以我找到了一种在 SQL 中执行此操作的方法。如果有人知道一种更 ruby​​ 的方式而不创建大量数据库查询,请加入。

scope :available, joins('LEFT JOIN orders 
    ON orders.delivery_slot_id = delivery_slots.id')
    .where("delivery_slots.limit > ( 
        SELECT COUNT(*) FROM orders 
        WHERE orders.delivery_slot_id = delivery_slots.id )
    ")
于 2013-05-29T22:15:10.243 回答
0
scope :available, lambda { 
  |delivery_slot| joins(:orders).
         where("limit > ?", order.count) 
}

尝试这个

于 2013-05-27T11:42:54.913 回答