2017-10-14 41 views
0

模式Rails的5 - 查詢協會「父」的名稱和數量「孩子」

用戶有客戶,其中有具有任務項目。

我試圖建立與陣列[名稱,計數]以發送到谷歌圖 - 我有所有的人,但一個解決:

def task_by_project(user) 
    task_arr = user.projects.joins(:tasks).where("tasks.completed = ?", "0").uniq.collect { |d| [d.name, d.tasks.count] }.to_a 
    task_arr.unshift(['Projects', 'Uncompleted Tasks']) 
    return task_arr 
end 

該查詢返回11項。這實際上就是這個用戶的所有條目。它完全繞過了where。有7個未完成的4個完成。

在我使其與循環略有不同的觀點:

<% current_user.projects.uniq.each do |project| %> 
     <%= link_to project.name + " || " + project.tasks.where(completed: 0).count.to_s + " tasks remaining currently", project, :class => "collection-item" %> 
    <% end %> 
    </div> 

我相當確信它與我的如何查詢關聯此深的誤解做。

END RESULT是我需要項目的名稱,並計算它有多少個任務。

我通過查詢加入Task回到ProjectProject.ID - 但我不知道如何做到這一點與整個集合。

(的「不印字」的目的是因爲其他明智我最終的[[['Projects', 'Tasks'], [['First Record, 2] ... ]]結果格式不GCharts格式。獻媚殺死它關閉-too-多)

回答

1

也許是這樣的?

projects = user.projects 
    .select("projects.name, COUNT(uncompleted_tasks.id) AS uncompleted_tasks_count") 
    .joins("LEFT OUTER JOIN tasks AS uncompleted_tasks ON uncompleted_tasks.project_id = projects.id AND uncompleted_tasks.completed = 0") 
    .group("projects.id") 
    .map { |project| [project.name, project.uncompleted_tasks_count] } 
+0

如果OP已爲該列設置了默認值,則應該不需要'completed:[0,nil]'。 – max

+0

我相信,如果你刪除'nil',那麼它將不包含沒有任何任務的項目。如果這是預期的情況,那麼'left_joins'也可以改爲'joins'。 – kaspernj

+0

不,因爲你正在做一個'LEFT OUTER JOIN',即使它們在連接中沒有任何匹配,也會返回行。我猜它是一個錯誤的枚舉或布爾型列被錯誤地定義爲一個整數。在這兩種情況下,它都應該有一個默認值,因爲你不想要一個null/indeterminate狀態。 – max

0

使用.pluck得到的列值,而不是

user.projects.left_joins(:tasks).where("tasks.completed = 0") 
    .distinct 
    .pluck('users.id, users.name, tasks.count') 
    .map { |a| a.pop(2) } 

.pluck是更爲有效,因爲它只是查詢傳遞給掐了列,並返回一個數組的數組,而不是加載大量的模型成記憶。

# => [[1, 'Frank', 0], [2, 'Muhammad', 5], [3, 'Jane', 3]] 

但是,除非您的名稱列是唯一的,否則應選擇用戶標識符以清除重複項。 .map { |a| a.pop(2) }擺脫結果數組中的id。

將記錄拉出數據庫並在其上調用.uniq是一個巨大的反模式。您將大量數據從數據庫中提取出來,然後在Ruby中整理出重複項。這可能導致嚴重的性能問題。

另外一種更好的方式來處理狀態是通過使用ActiveRecord::Enum

class Task 
    enum :status, [:incomplete, :complete, :deleted] 
end 

可以讓你查詢:

Task.incomplete 
Task.completed 

,讓您interogration和變異方法:

task.complete? 
task.complete! 

你可以這樣使用它:

user.projects.left_joins(:tasks).where(tasks: Task.incomplete) 
    .distinct 
    .pluck('users.id, users.name, tasks.count') 
    .map { |a| a.pop(2) } 
+0

編輯,我意識到你需要選擇'users.id'來獲得適當的不同查詢。否則,結果將按名稱顯示,因此具有相同名稱和計數的兩個用戶將作爲同一行而不是兩行返回。 – max

+0

感謝深層次的思考。 Task.'completed'實際上是一個枚舉,出於某種原因我完全忘記了這個幫助器。出於某種原因,我也沒有想過要採用多於一列(我不知道它是否構建了一個數組) – DNorthrup

+0

不要命名枚舉完整 - 將其命名爲狀態或狀態或其他任何但不是不能錯誤。 – max