0

私は2つのモデルを持っています:

DeliverySlot has_many :orders オーダーの所属先 :delivery_slot

デリバリー スロットには、保持できる注文数の制限があります。利用可能なすべての配信スロットを提供するスコープを作成したいと考えています。利用可能な配送スロットとは、関連する注文の制限に達していない配送スロットです。

私の試みは次のようになります:

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

whereRails は、適切に渡すと条件のサブクエリとして使用できるほどスマートです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

orders_countRails は、各 の列を自動的にインクリメントおよびデクリメントしDeliverySlotます。また、インデックスが作成されているため、クエリが非常に高速です。

于 2013-05-29T22:59:44.420 に答える