Rails: find_by_sql и виртуальный столбец - PullRequest
12 голосов
/ 24 февраля 2009

Я хочу отобразить список с тегами плюс количество элементов (в моем примере «Задачи») для каждого тега.

Для этой цели я создал следующий метод в моей модели тегов:

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

Метод возвращает правильные имена тегов, но по какой-то причине учетные записи задач отсутствуют в результате. Результат выглядит как

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

Поскольку этот подход, похоже, не работает, мне интересно, как Rails-way решает такую ​​задачу. Спасибо!

Ответы [ 2 ]

21 голосов
/ 25 февраля 2009

Счетчик есть, вы просто не можете его увидеть, поскольку taskcount не является атрибутом, который Rails создает для этого класса Task, потому что это не столбец, который он может видеть. Вы должны использовать атрибуты вызова, чтобы найти его. Пример:

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

Tag.find_with_count.each do |t|
  puts "#{t.name}: #{t.taskcount}"
end
9 голосов
/ 24 февраля 2009

«Путь 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.find_by_count на Tag.active. Используйте это так:

Tag.active.each do |t|
  puts "#{t.name} (#{t.tag_tasks_count})"
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...