2017-01-30 24 views
1

У меня модель заказа и модель контейнера с областью, как показано ниже:Рельсы активная запись сфера на основе подсчета has_many объема

class Order < ActiveRecord::Base 
    has_many :containers, inverse_of: :order, dependent: :destroy 
end 

class Container < ActiveRecord::Base 
    scope :full_pickup_ready, -> { where.not(full_pickup_ready_date: nil) } 
end 

Модель порядок имеет поле вызова quantity, который представляет собой количество контейнеров под заказ требует, но необязательно, размера ассоциации контейнеров, поскольку не все данные контейнера вводятся во время создания заказа.

Я хотел бы иметь область действия модели заказа, основанную на том, меньше ли количество контейнеров с полным_pickup_ready_date, чем поле количества заказа.

Я знаю, что может использовать сливать на модели для того, чтобы получить доступ к сферам на контейнерах, как это:

def self.at_origin 
    joins(:containers).merge(Container.full_pickup_ready).uniq 
end 

, но как я могу ограничить объем для заказов, где общее количество контейнеров с full_pickup_ready_date является меньше, что поле количества в порядке?

UPDATE: это достаточно близко, но я не думаю, что с помощью select эффективен:

includes(:containers).select {|o| o.containers.full_pickup_ready.size < o.quantity } 
+0

Что является 'carrier_collected_full' объект? это коллекция или просто контейнер? – kurenn

+0

Извините, что я копировал неправильный масштаб (у меня есть несколько областей с аналогичной проблемой). Предполагалось, что он будет областью в контейнерной модели «full_pickup_ready».Я изменил это, чтобы использовать область «full_pickup_ready». –

ответ

2

Если вы готовы отказаться от повторного использования объема на Container, то вы должны быть в состоянии использовать что-то вроде:

# scope on Order 
joins(:containers) 
    .group("orders.id") 
    .having("count(CASE WHEN full_pickup_ready_date THEN 1 END) < orders.quantity") 
+0

Спасибо - использование CASE в счетчике умно и дает мне именно то, что я хочу. Мне пришлось изменить его на «CASE WHEN», когда full_pickup_ready_date IS NOT NULL THEN 1 END', но в идеале. Я награду щедростью, когда это позволит мне (примерно через 7 часов) –

1

Я думаю, что вам нужно, чтобы получить этот SQL запрос, чтобы работать для вас. Поэтому идея состоит в том, чтобы правильно получить SQL-запрос, а затем перевести его в «Rails».

SQL

Если я прав, то это должно быть SQL запросов вы хотите достичь. Может быть, вы можете попробовать его в rails db

SELECT orders.* 
FROM orders JOIN containers 
WHERE containers.id = orders.id 
AND ( 
    SELECT COUNT(containers.id) 
    FROM containers 
    WHERE containers.full_pickup_ready_date IS NOT NULL 
) < orders.quantity; 

ActiveRecord

Если это правильный запрос, то мы можем сделать это с помощью реек

Order.joins(:containers).where("(SELECT COUNT(containers.id) FROM containers WHERE containers.full_pickup_ready_date IS NOT NULL) < orders.quantity") 

Это должно вернуть отношения ActiveRecord. Вы также можете сделать это:

sql = %{ 
    SELECT orders.* 
    FROM orders JOIN containers 
    WHERE containers.id = orders.id 
    AND ( 
    SELECT COUNT(containers.id) 
    FROM containers 
    WHERE containers.full_pickup_ready_date IS NOT NULL 
) < orders.quantity; 
}.gsub(/\s+/, " ").strip 

Order.find_by_sql(sql) 

Просто добавьте это в метод класса (лучше, чем области видимости ИМХО), и вы хорошо идти.

Итак, ваш класс Order должен выглядеть следующим образом:

class Order < ActiveRecord::Base 
    has_many :containers, inverse_of: :order, dependent: :destroy 

    def self.gimme_a_query_name 
    joins(:containers).where("(SELECT COUNT(containers.id) FROM containers WHERE containers.full_pickup_ready_date IS NOT NULL) < orders.quantity") 
    end 

    def self.gimme_another_query_name 
    sql = %{ 
     SELECT orders.* 
     FROM orders JOIN containers 
     WHERE containers.id = orders.id 
     AND ( 
     SELECT COUNT(containers.id) 
     FROM containers 
     WHERE containers.full_pickup_ready_date IS NOT NULL 
    ) < orders.quantity; 
    }.gsub(/\s+/, " ").strip 
    find_by_sql(sql) 
    end 
end 

У меня нет никакого способа, чтобы попробовать это, но он должен работать с несколько подстройкой, чтобы получить право SQL запросов.

Я надеюсь, что эта помощь!

+0

Спасибо, я вижу, как это будет работать, но ответ от @gwcodes немного более краток, поэтому я пойду с этим. –