Подтвердить что ты не робот

Rails: find_by_sql и виртуальный столбец

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

Для этой цели в моей модели 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

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

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

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

4b9b3361

Ответ 1

Счет есть, вы просто не можете его увидеть, поскольку 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

Ответ 2

"Rails way" - использовать 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 в таблицу "Tag".

Если вы добавили тег 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