我有2个型号:
DeliverySlot has_many:orders 订单belongs_to:delivery_slot
交货时段限制了他们可以持有的订单数量。我想创建一个范围来提供所有可用的交付槽。可用的交付槽是未达到相关订单限制的槽。
我的尝试看起来像:
scope :available, where("limit > ?", order.count).joins(:orders)
order.count是上面的伪代码。
答案 0 :(得分:2)
要像设置设置一样执行此操作,您需要使用orders.count
而不是order.count
,因为您指的是关联。这会提示ActiveRecord汇编类似SELECT COUNT(*) FROM orders WHERE delivery_slot_id = 1
的查询。
Rails实际上非常聪明,当你恰当地传递它时,where
条件中的子查询可以作为子查询使用,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_count
的{{1}}列,并且由于它已编入索引,因此查询速度非常快。
答案 1 :(得分:0)
scope :available, lambda {
|delivery_slot| joins(:orders).
where("limit > ?", order.count)
}
试试这个
答案 2 :(得分: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 )
")