具有条件的列的计数器缓存?

ssc*_*rus 37 ruby-on-rails ruby-on-rails-3

我不熟悉计数器缓存的概念,并且在我的应用程序主页上有一些天文加载时间,我相信我需要继续它.

我需要实现的大多数计数器缓存都附加了某些(简单)条件.例如,这是一个常见的查询:

@projects = employee.projects.where("complete = ?", true).count
Run Code Online (Sandbox Code Playgroud)

N+1当我显示一个列出公司每个员工的项目计数的表单时,我遇到了上面的查询问题.

途径

我真的不知道我在做什么,所以请指正!

# new migration
add_column :employees, :projects_count, :integer, :default => 0, :null => false

# employee.rb
has_many :projects

# project.rb
belongs_to :employee, :counter_cache => true
Run Code Online (Sandbox Code Playgroud)

迁移后...是我需要做的吗?

我如何在我提到的条件下工作,以尽量减少加载时间?

Mik*_*wis 27

关于条件counter_cache,我会阅读这篇博文.

您应该做的一件事是将以下内容添加到迁移文件中:

 add_column :employees, :projects_count, :integer, :default => 0, :null => false

 Employee.reset_column_information

 Employee.all.each do |e|
   Employee.update_counters e.id, :projects_count => e.projects.length
 end
Run Code Online (Sandbox Code Playgroud)

因此,您当前的项目计数可以迁移到projects_count与每个Employee对象关联的新项目.在那之后,你应该好好去.

  • 是的,所以你要添加一个新列并做类似的事情:Employee.all.each do {| e | Employee.update_counters(e.id,:completed_projects_count => e.projects.where(:complete => true).count (3认同)
  • @Mike Lewis - 我如何实施条件? (2认同)

phi*_*kov 13

检查counter_culture gem:

counter_culture :category, column_name: Proc.new {|project| project.complete? ? 'complete_count' : nil }
Run Code Online (Sandbox Code Playgroud)

  • 埋藏在自述文件的底部是它不适用于多态关系. (5认同)
  • 现在,counter_culture支持一个级别的多态关联。 (2认同)

Nic*_*vre 8

您不应该使用"counter_cache"而是使用自定义列:

rails g migration AddCompletedProjectsCountToEmployees completed_projects_count:integer
Run Code Online (Sandbox Code Playgroud)

(, :default => 0如果需要,添加到add_column行)

rake db:migrate
Run Code Online (Sandbox Code Playgroud)

然后使用回调

class Project < ActiveRecord::Base
  belongs_to :employee

  after_save :refresh_employee_completed_projects_count
  after_destroy :refresh_employee_completed_projects_count

  def refresh_employee_completed_projects_count
    employee.refresh_completed_projects_count
  end
end

class Employee
  has_many :projects

  def refresh_completed_projects_count
    update(completed_projects_count:projects.where(completed:true).size)
  end
end
Run Code Online (Sandbox Code Playgroud)

添加列后,您应该在控制台或迁移文件中进行初始化(在def up中):

Employee.all.each &:refresh_completed_projects_count
Run Code Online (Sandbox Code Playgroud)

然后在您的代码中,您应该调用employee.completed_projects_count以访问它


mon*_*ike 6

而不是update_counters我用update_all

您不需要这Employee.reset_column_information条线,而且速度更快,因为您正在执行单个数据库调用

Employee.update_all("projects_count = (
   SELECT COUNT(projects.id) FROM projects 
   WHERE projects.employee_id = employees.id AND projects.complete = 't')")
Run Code Online (Sandbox Code Playgroud)