2009-04-25 3 views
5

В моем интернет-магазине заказ готов к отправке, если он находится в «разрешенном» состоянии и не имеет каких-либо связанных грузов. Сейчас я делаю это:Найти все объекты без связанных объектов has_many

class Order < ActiveRecord::Base 
    has_many :shipments, :dependent => :destroy 

    def self.ready_to_ship 
     unshipped_orders = Array.new 
     Order.all(:conditions => 'state = "authorized"', :include => :shipments).each do |o| 
      unshipped_orders << o if o.shipments.empty? 
     end 
     unshipped_orders 
    end 
end 

Есть ли лучший способ?

ответ

8

Вы также можете запрос об ассоциации с помощью обычного найти синтаксис:

Order.find(:all, :include => "shipments", :conditions => ["orders.state = ? AND shipments.id IS NULL", "authorized"]) 
+0

Это не сработает. Поскольку это ассоциация has_many, внешний ключ хранится в таблице отправлений. –

+0

Вот почему мы присоединяемся к идентификатору NULL –

+0

Право, мое плохое (я сосать на SQL). Во всяком случае, это работает, за исключением того, что вам нужно заменить «статус» на «состояние» (для моего конкретного случая) и добавить «и» перед «shipmentments.id». Внесите эти изменения, и я отвечу на этот вопрос. –

1

Один из вариантов заключается в том, чтобы поставить shipment_count на заказ, где он будет автоматически обновляться с количеством отправлений, которые вы прикрепляете к нему. Тогда вы просто

Order.all(:conditions => [:state => "authorized", :shipment_count => 0]) 

В качестве альтернативы, вы можете получить ваши руки грязные с некоторыми SQL:

Order.find_by_sql("SELECT * FROM 
    (SELECT orders.*, count(shipments) AS shipment_count FROM orders 
    LEFT JOIN shipments ON orders.id = shipments.order_id 
    WHERE orders.status = 'authorized' GROUP BY orders.id) 
    AS order WHERE shipment_count = 0") 

Проверьте, что перед использованием, поскольку SQL не совсем мой мешок, но я думаю, что это близко направо. Я получил его для работы на аналогичных устройствах объектов на моей производственной БД, которая является MySQL.

Обратите внимание, что если у вас нет указателя на orders.status, я бы настоятельно советовал ему!

Что делает запрос: подзапрос захватывает все количество заказов для всех заказов, находящихся в разрешенном состоянии. Внешние фильтры запросов, которые перечислены только для тех, у которых количество отправлений равно нулю.

Там, наверное, еще один способ, которым Вы могли бы сделать это, немного парадоксально:

"SELECT DISTINCT orders.* FROM orders 
    LEFT JOIN shipments ON orders.id = shipments.order_id 
    WHERE orders.status = 'authorized' AND shipments.id IS NULL" 

захватить все заказы, которые уполномочены и не имеют запись в таблице отгрузок;)

+0

Ваш синтаксис является фиктивным, должен быть: conditions => {: state => "authorized",: shipment_count => 0} ... другими словами, используйте хэш, а не массив. –

12

в Rails 3 с использованием AREL

Order.includes('shipments').where(['orders.state = ?', 'authorized']).where('shipments.id IS NULL') 
Смежные вопросы