2009-02-24 48 views
12

我想顯示一個帶有標籤的列表以及每個標籤的元素數量(在我的示例中爲「任務」)。Rails:find_by_sql和虛擬列

爲此,我創建了我的標籤模型下面的方法:

def self.find_with_count 
    find_by_sql 'SELECT 
       Tag.name, 
       COUNT(Tag.name) AS taskcount 
       FROM 
       tags AS Tag 
       INNER JOIN tags_tasks tt ON tt.tag_id = Tag.id 
       INNER JOIN tasks t ON tt.task_id = t.id 
       WHERE 
       t.finished = 0 
       AND t.deleted = 0 
       GROUP BY 
       Tag.name 
       ORDER BY 
       Tag.name' 
end 

該方法返回正確的標籤名稱,但由於某些原因,taskcounts不在結果。結果看起來像

[#<Tag name: "hello">, #<Tag name: "world">] 

由於這種方法似乎沒有工作,我想知道什麼Rails的方式來完成這樣的任務。謝謝!

+0

優秀的問題!我知道這是一箇舊帖子,但它爲我正在處理的一個大項目節省了我的時間......所以,謝謝! – dennismonsewicz 2013-03-13 19:53:25

回答

21

計數是存在的,你就不能看到它,因爲taskcount不是Rails的創建該類任務的屬性,因爲它不是一個列,它可以看到。您必須使用屬性調用來查找它。 樣品:

class Tag < ActiveRecord::Base 
    ... 
    def taskcount 
    attributes['taskcount'] 
    end 
end 

Tag.find_with_count.each do |t| 
    puts "#{t.name}: #{t.taskcount}" 
end 
9

的 「Rails的方式」 是使用counter_cache

class Tag < ActiveRecord::Base 
    has_many :tag_tasks 
    has_many :tasks, :through => :tag_tasks 
end 

# the join model 
class TagTask < ActiveRecord::Base 
    belongs_to :tag, :counter_cache => true 
    belongs_to :task 
end 

class Task < ActiveRecord::Base 
    has_many :tag_tasks 
    has_many :tags, :through => :tag_tasks 
end 

這就需要你的 '標籤' 表中新增tag_tasks_count列。

如果添加named_scope到標籤,像這樣:

class Tag ... 
    named_scope :active, lambda { { :conditions => { 'deleted' => 0, 'finished' => 0 } } } 
end 

然後你就可以用Tag.active取代所有Tag.find_by_count。使用這樣的:

Tag.active.each do |t| 
    puts "#{t.name} (#{t.tag_tasks_count})" 
end 
+0

未發現計數器緩存或實際命名的作用域。非常好 - 謝謝解釋。 – 2009-02-25 02:04:45

+0

感謝與計數器緩存的想法,這似乎是比使用find_by_sql更乾淨的解決方案。 – dhofstet 2009-02-25 08:25:57