2016-03-15 7 views
0
структуры

данных выглядит следующим образом:Итоговые значения по атрибуту, возвращенного has_many через

class Job 
    has_many job_sections 
    has_many job_products, through job_sections 
end 

class JobSection 
    belongs_to job 
    has_many job_products 
end 

class JobProduct 
    belongs_to product 
    belongs_to job_section 
end 

Когда я звоню job.job_products я мог бы в конечном итоге с чем-то вроде этого:

#<JobProduct:0x007ff4128b0ca0 
    id: 18133, 
    product_id: 250, 
    quantity: 3, 
    frozen_cache: {}, 
    discount: 0.0, 
#<JobProduct:0x007ff4128b00c0 
    id: 18134, 
    product_id: 250, 
    quantity: 1, 
    frozen_cache: {}, 
    discount: 0.0] 

, как вы может видеть, что product_id идентичен в обоих случаях. Как объединить содержимое массивов по идентификатору продукта, чтобы я извлекал и действовал на них как агрегированные значения?

В некотором смысле, я должен иметь возможность действовать на продуктах работы по их product_id, а не их id.

Эффективно в результате чего-то вроде этого ...

[#<SomeFancySeerviceObjectMaybe? 
    product_id: 250, 
    quantity: 4, 
    frozen_cache: {}, 
    discount: 0.0] 

ли я выбрать для маленькой Plain Old рубинового объект для обработки их всех, или мне придется пересмотреть архитектуру этого, или там (надеюсь,!) немного секретного соуса Rails, который может помочь мне?

* FYI Job Section - это недавнее дополнение к архитектуре, и я не думаю, что его особенно хорошо продумали. Однако я не могу тратить слишком много времени на то, что уже сделано. Эта настройка не идеальна, я, вероятно, шестой разработчик за столько лет, чтобы начать разбирать это отдельно.

Ваши предложения приветствуются. Спасибо

ответ

1

В SQL это будет что-то вроде этого:

SELECT SUM(quantity) 
FROM job_products 
WHERE product_id = 250 
GROUP BY product_id 

Вы можете сделать это в ActiveRecord тоже. Если вы просто хотите, целое число, вы можете использовать pluck:

total_quantity = job.job_products. 
    group(:product_id). 
    pluck("SUM(job_products.quantity)"). 
    first 

Вы также можете pluck несколько столбцов, если вы хотите (в Rails 4+), поэтому она возвращает массив. Поэтому, если вы хотите получить среднюю скидку в одно и то же время, это легко.

Если вы предпочитаете экземпляр JobProduct, вы можете получить его тоже, но в вашем случае многие атрибуты будут nil из-за группировки. Но вы можете сказать:

summary = job.job_products. 
    group(:product_id). 
    select("SUM(job_products.quantity) AS total_quantity"). 
    first 

И вы получите только для чтения JobProduct с дополнительным атрибутом имени total_quantity. Итак, вы можете сделать summary.total_quantity. Но из-за группировки summary будет иметь nilid, discount и т. Д. В принципе, он будет иметь только атрибуты, соответствующие вашим вещам select. Это немного странно, но иногда это позволяет писать методы, которые работают как на «реальных» JobProduct, так и на этих сводных версиях.

+0

ударить ноготь по голове, отличный ответ –