Проблема с active-записью и sql - PullRequest
0 голосов
/ 06 октября 2010

У меня небольшая проблема: я не могу составить sql-запрос внутри AR.

Итак, у меня есть модели Project и Task, Project has_many Tasks. Task имеет aasm-поле (то есть "status"; но это не имеет значения, я могу быть простым int или строковым полем).

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

Вот так, просто посмотрите:

  • Первый проект (1 активный, 2 ожидающих, 10 решено)
  • Вторые проекты (4 активный, 2 ожидающих, 2 решенных)

Итак, конечно, я могу сделать это с @projects = Project.all и затем в поле зрения:

- @projects.each do |project| 
  = project.title
  = project.tasks(:conditions => {:status => "active"}).count #sure it should be in model, just for example
  = project.tasks(:conditions => {:status => "pending"}).count
  # ...
- end

Это хорошо, но делает 1 + N * 3 (для 3 состояний задачи) запросов, я хочу 1. Вопрос прост: how?.

Ответы [ 4 ]

0 голосов
/ 07 октября 2010

Итак, правильный ответ:

Projects.all(:joins  => :tasks, 
             :select => 'projects.*, 
                         sum(tasks.status="pending") as pending_count, 
                         sum(tasks.status = "accepted") as accepted_count, 
                         sum(tasks.status = "rejected") as rejected_count', 
             :group  => 'projects.id')
0 голосов
/ 06 октября 2010

Вы можете сделать поиск с группировкой и подсчетом.Что-то вроде:

status_counts = project.tasks.find(:all, 
                                   :group => 'status', 
                                   :select => 'status, count(*) as how_many')

Это вернет вам список Task -подобных объектов с атрибутами status и how_many, которые вы затем сможете использовать для предоставления вашего резюме.Например,

<%= status_counts.map { |sc| "#{sc.how_many} #{sc.status} }.to_sentence %>
0 голосов
/ 06 октября 2010

Возможно, вы могли бы, в вашем контроллере проекта:

  1. Получить все ваши проекты: Project.all
  2. Получить все ваши задачи: Task.all

Затем создайте хэш с чем-то вроде

@statuses = Hash.new
@tasks.each do |t|
  @statuses[:t.project_id][:t.status] += 1
end

А затем используйте его в своем представлении:

First project (<%= @statuses[:@project.object_id][:active] %> active)

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

Также, было бы интересно именованные области , например Task.active.

0 голосов
/ 06 октября 2010

Я бы предложил использовать кэш счетчика в модели вашего проекта, чтобы избежать необходимости пересчитывать все задачи на каждом отображении страницы индекса - иметь active_count, pending_count и resolved_count и обновлять их всякий раз, когда задача меняет состояние.

Если вы просто хотите изменить существующий код, попробуйте:

project.tasks.count(:conditions => "status = 'active'")

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

project.tasks.active.count

EDIT

Хорошо, я наполовину сплю - у вас неправильное впечатление от вашего вопроса: /

Да, вы можете сделать это одним запросом - используйте find_by_sql, чтобы получить ваши проекты вместе с сгруппированными подсчетами для задач. Вы сможете получить доступ к количеству групп в результирующем массиве проектов.

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