2009-02-24 8 views
12

chcę, aby wyświetlić listę z tagów plus liczbę elementów (w moim przykładzie „Zadania”) dla każdego tagu.szyn: find_by_sql i wirtualnych kolumny

W tym celu stworzyłem następujące metody w moim modelu tag:

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 

metoda zwraca poprawnych nazw znaczników, ale z jakiegoś powodu nie są taskcounts w wyniku. Wynik wygląda

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

Jako takie podejście nie wydaje się działać, zastanawiam się co szynach-way jest do osiągnięcia takiego zadania. Dzięki!

+0

Doskonałe pytanie! Wiem, że to stary post, ale uratował mnie na dużym projekcie, nad którym pracuję ... więc, dzięki! – dennismonsewicz

Odpowiedz

21

Hrabia ma, po prostu nie można zobaczyć go od taskcount nie jest atrybutem Rails tworzy dla tej klasy zadanie, ponieważ nie jest to kolumna, że ​​można go zobaczyć. Musisz użyć atrybutu call, aby go znaleźć. Próbka:

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

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

Dzięki ... to było pomocne – bragboy

9

z "Rails Way" jest użycie 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 

Wymaga to dodanie kolumny tag_tasks_count na stole 'Tag'.

Jeśli dodać named_scope Tag tak:

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

Następnie można wymienić wszystkie Tag.find_by_count z Tag.active. Używaj go tak:

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

Nie wykrył pamięci podręcznej licznika lub nazwanych zakresów. Bardzo miło, dzięki za wyjaśnienie. –

+0

Dzięki za pomysł z licznikiem pamięci podręcznej, który wydaje się być czystszym rozwiązaniem niż przy użyciu find_by_sql. – dhofstet