ActiveRecord 计数器缓存功能似乎会导致计数器缓存增加两次。我看到这种行为的场景是当我有两个模型时has_many :through
通过连接模型相互建立关系(即:Teacher
有很多Student
通过Classroom
)。当使用has_many :through
生成的直接关联教师和学生的方法(无需手动创建连接记录)计数增加了 2 倍。例子:teacher.students << Student.create(name: "Bobby Joe")
causes teacher.students_count
增加 2。
请帮助我找到一个解决方案来减轻或消除这个问题,同时允许我继续使用内置计数器缓存和通过has_many :through
关系。
我花了很多时间寻找解决方案,并将问题提取到一个小型测试应用程序中,这是我可以创建的最简单的失败示例。希望帮助我解决这个问题所需的任何其他详细信息应该在下面。
示例架构和模型:
create_table :teachers do |t|
t.string :name
t.integer :students_count, default: 0
t.timestamps
end
class Teacher < ActiveRecord::Base
has_many :classrooms
has_many :students, :through => :classrooms
end
create_table :students do |t|
t.string :name
t.integer :teachers_count, default: 0
t.timestamps
end
class Student < ActiveRecord::Base
has_many :classrooms
has_many :teachers, :through => :classrooms
end
create_table :classrooms do |t|
t.references :teacher
t.references :student
t.timestamps
end
class Classroom < ActiveRecord::Base
belongs_to :student, :counter_cache => :teachers_count
belongs_to :teacher, :counter_cache => :students_count
end
这是一个简短的 Rails 控制台会话,显示了所采取的步骤以及 Rails 正在执行的事实two更新到teachers
增加students_count
:
1.9.2-p290 :001 > t = Teacher.create(name: "Miss Nice")
SQL (9.7ms) INSERT INTO "teachers" ("created_at", "name", "students_count", "updated_at") VALUES (?, ?, ?, ?) [["created_at", Tue, 28 Feb 2012 03:31:53 UTC +00:00], ["name", "Miss Nice"], ["students_count", 0], ["updated_at", Tue, 28 Feb 2012 03:31:53 UTC +00:00]]
=> #<Teacher id: 1, name: "Miss Nice", students_count: 0, created_at: "2012-02-28 03:31:53", updated_at: "2012-02-28 03:31:53">
1.9.2-p290 :002 > t.students << Student.new(name: "Mary Ann")
SQL (0.3ms) INSERT INTO "students" ("created_at", "name", "teachers_count", "updated_at") VALUES (?, ?, ?, ?) [["created_at", Tue, 28 Feb 2012 03:32:12 UTC +00:00], ["name", "Mary Ann"], ["teachers_count", 0], ["updated_at", Tue, 28 Feb 2012 03:32:12 UTC +00:00]]
SQL (0.3ms) INSERT INTO "classrooms" ("created_at", "student_id", "teacher_id", "updated_at") VALUES (?, ?, ?, ?) [["created_at", Tue, 28 Feb 2012 03:32:12 UTC +00:00], ["student_id", 1], ["teacher_id", 1], ["updated_at", Tue, 28 Feb 2012 03:32:12 UTC +00:00]]
SQL (0.2ms) UPDATE "students" SET "teachers_count" = COALESCE("teachers_count", 0) + 1 WHERE "students"."id" = 1
Teacher Load (0.1ms) SELECT "teachers".* FROM "teachers" WHERE "teachers"."id" = 1 LIMIT 1
SQL (0.1ms) UPDATE "teachers" SET "students_count" = COALESCE("students_count", 0) + 1 WHERE "teachers"."id" = 1
SQL (0.0ms) UPDATE "teachers" SET "students_count" = COALESCE("students_count", 0) + 1 WHERE "teachers"."id" = 1
Student Load (0.2ms) SELECT "students".* FROM "students" INNER JOIN "classrooms" ON "students"."id" = "classrooms"."student_id" WHERE "classrooms"."teacher_id" = 1
=> [#<Student id: 1, name: "Mary Ann", teachers_count: 1, created_at: "2012-02-28 03:32:12", updated_at: "2012-02-28 03:32:12">]
如果有人想仔细查看的话,我已将整个测试应用程序放在 github 上(https://github.com/carlzulauf/test_app https://github.com/carlzulauf/test_app)。我还创建了一个单元测试来演示该问题但未能通过(https://github.com/carlzulauf/test_app/blob/master/test/unit/classroom_test.rb https://github.com/carlzulauf/test_app/blob/master/test/unit/classroom_test.rb)