У меня есть анти-шаблон в моем коде Rails 3, и мне было интересно, как это сделать правильно.
Допустим, клиент заказывает картофель фри и гамбургер. Я хочу узнать, был ли такой заказ размещен ранее. Для простоты каждый элемент может быть заказан только один раз за заказ (так что «двух гамбургеров, пожалуйста») и повторных заказов тоже нет.
Модели:
Order (attributes: id)
has_many :items_orders
has_many :items, :through => :items_orders
Item (attributes: id, name)
has_many :items_orders
has_many :orders,:through => :items_orders
ItemsOrder (attributes: id, item_id, order_id)
belongs_to :order
belongs_to :item
validates_uniqueness_of :item_id, :scope => :order_id
Способ, которым я делаю это сейчас, заключается в получении всех заказов, которые включают хотя бы одну из позиций. Затем я перебираю их, чтобы найти соответствующий порядок. Излишне говорить, что это не очень хорошо масштабируется и не выглядит красиво.
order = [1, 2]
1 и 2 соответствуют идентификаторам предметов картофеля фри и гамбургеров.
candidates = Order.find(
:all,
:include => :items_orders,
:conditions => ["items_orders.item_id in (?)", order])
previous_order = nil
candidates.each do |candidate|
if candidate.items.collect{|i| i.id} == order
previous_order = candidate
break
end
end
Я использую MySQL и Postgress, поэтому я также открыт для стандартного решения SQL, которое игнорирует большую часть ActiveRecord.