Как извлечь «таблицу» из массива ActiveRecords в Rails? - PullRequest
7 голосов
/ 15 августа 2010

У меня есть несколько похожих моделей (ContactEmail, ContactLetter, ContactPostalcard).

Каждый экземпляр (запись) в, скажем, ContactEmail означает, что конкретный шаблон электронной почты был отправлен конкретному контакту.

Итак, каждый (например, ContactEmail) belongs_to :contact

Итак, в модели ContactEmail есть атрибут ContactEmail.contact_id.

Каждый контакт имеет виртуальный атрибут company_name.

Итак, когда я напишу следующее, я получу все электронные письма, отправленные в рамках определенного набора условий (в данном случае, времени):

@sent_emails = ContactEmail.find(:all, :conditions => "conditions here")

Итак, @sent_emails.size сообщит мне сумму всех отправленных писем.

Моя задача: как извлечь дополнительную детализацию от уникальной компании для разных моделей?

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

FROM 8/1/10 TO 8/10/10 (where the dates are dynamic)

                Calls       Letter      Postalcards
Company 1         4           2             4
Company 2        10           4             6
Company 3         2           3             4

Таким образом, у Company3 есть 2 Calls, что означает, что было две записи ContactCalls, когда sent_date попадает между двумя датами, и где связанный контакт принадлежит Company 3.

Компания 1-3 не установлена ​​заранее. Его необходимо извлечь из пула ContactCalls, ContactLetters и ContactPostalcards .....

Проблема в том, что я не знаю, что это за компании. Они являются атрибутами части контактов каждой отдельной записи. Так что в некоторых случаях у меня может быть Company2 имеет 0 букв.

Спасибо за любые рекомендации! :)

Как мне найти компанию по заданной записи для модели ContactEmail:

ContactEmail.contact.company.name

Это вернет ассоциированную компанию для определенного ContactEmail

Ответы [ 4 ]

2 голосов
/ 20 августа 2010

Это должно сделать это красиво:

    list = Contact.find :all,
      :select => "companies.name company_name, COUNT(contact_emails.id) email_count, COUNT(contact_letters.id) letter_count, COUNT(contact_postalcards.id) postalcard_count",
      :joins => [
        "LEFT JOIN companies ON company.id = contact.company_id",
        "LEFT JOIN contact_emails ON contact_emails.contact_id = contacts.id",
        "LEFT JOIN contact_letters ON contact_letters.contact_id = contacts.id",
        "LEFT JOIN contact_postalcards ON contact_postalcards.contact_id = contacts.id"
      ],
      :group => "companies.id"

      list.each do |item|
        p item.company_name, item.email_count, item.letter_count, item.postalcard_count
      end
0 голосов
/ 17 августа 2010

Если вы действительно хотите, чтобы все контакты имели количество всех этих отношений, было бы неплохо использовать counter_cache.

http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html - найти кэш счетчика на этой странице

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

Что вам нужно сделать, это добавить столбцы «emails_count», «letters_count» и «postcards_count» в таблицу «контактов», сначала обновить ее с нужным счетчиком и объявить отношения has_many следующим образом:

class Contact < ActiveRecord::Base
  has_many :emails, :class_name => 'ContactEmail', :counter_cache => 'emails_count'
  # so on for other columns
end

С этими настройками все, что вам нужно сделать, это запросить ваши контакты и проверить их кеш счетчика для отображения вашей таблицы.Это число будет автоматически обновляться рельсами при каждом создании или уничтожении элемента для этого контакта.

0 голосов
/ 18 августа 2010

О, так я сначала неправильно понял ваш вопрос.Я думаю, что наконец-то понял, что вы имеете в виду.

Так что, действительно, единственный хороший способ сделать то, что вы хотите (то есть извлечь все данные из всех этих таблиц), - это включить include при запросе контактов:

@contacts = Contact.all :include => [:contact_emails, :contact_letters, :contact_postal_cards]

Это сгенерирует 4 запроса, выбрав все данные из этих 4 таблиц и заполнив их контакты соответствующим образом, чтобы вы могли перемещаться по объектам контакта любым способом, каким вам нравится заполнять вашу таблицу.

Наконец, вы упоминаете, что ваша таблица будет сгруппирована по компаниям, а не по контактам, поэтому я предполагаю, что несколько контактов могут иметь одно и то же имя компании.Если это так, вы можете сгруппировать свою коллекцию по 'company_name', например так:

@companies = @contacts.group_by &:company_name

Это создаст хеш-код, подобный следующему:

{'Company 1' => [contact_1, contact_3], 'Company 2' => [contact_4]}

Имея эти, вы можетесгенерируйте свою таблицу примерно так:

<% @companies.each do |company_name, contacts| %>
    Company: <%= company_name %>
    <% contacts.each do |contact| %>
       Contact: <%= contact.name %>
          Emails : <%= contact.contact_emails.map(&:email).split(',') %>
          etc..
    <% end %>
<% end %>
0 голосов
/ 17 августа 2010

По моему мнению, попытка извлечь эти данные в одном запросе (что, я полагаю, вы хотите сделать) - это немного излишне.Я бы выполнил один запрос для каждого типа с опцией :group => company_name.Затем я объединил бы результаты, используя код Ruby, чтобы у меня была некоторая структура данных, которая позволяет легко отображать (возможно, хэш хэшей, например, {'Company 1' => {'Calls' => 5, 'Letter' => 0, 'Postalcards' => 3'}...}.

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