Найти все объекты без связанных объектов has_many - PullRequest
5 голосов
/ 25 апреля 2009

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

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

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

Ответы [ 3 ]

12 голосов
/ 17 июля 2012

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

Order.includes('shipments').where(['orders.state = ?', 'authorized']).where('shipments.id IS NULL')
8 голосов
/ 25 апреля 2009

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

Order.find(:all, :include => "shipments", :conditions => ["orders.state = ? AND shipments.id IS NULL", "authorized"])
3 голосов
/ 25 апреля 2009

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

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"

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...