似乎ActiveRecord的counter_cache功能可能导致计数器缓存递增两次。我看到这种行为的情况是当我有两个模型通过连接模型彼此具有has_many :through
关系时(即:Teacher
有许多Student
到{{1 }})。使用Classroom
生成的方法直接关联教师和学生(无需手动创建连接记录)时,计数会增加2倍。示例:has_many :through
导致teacher.students << Student.create(name: "Bobby Joe")
增加2。
请允许我找到一个解决方案来减轻或消除此问题,同时允许我通过teacher.students_count
关系继续使用内置计数器缓存和质量分配。
我花了很多时间寻找解决方案并将问题提取到一个小型测试应用程序,这是我可以创建的最简单的失败示例。任何有助于我解决此问题的其他细节都应该在下面。
示例模式和模型:
has_many :through
这是一个简短的rails控制台会话,显示了所采取的步骤以及rails正在执行两次更新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
以增加teachers
的事实:
students_count
如果有人想要仔细观察(https://github.com/carlzulauf/test_app),我已将整个测试应用程序放在github上。我还创建了一个单元测试来演示问题并且无法通过(https://github.com/carlzulauf/test_app/blob/master/test/unit/classroom_test.rb)
答案 0 :(得分:12)
到目前为止,我的研究告诉我这可能是一个错误。以下是针对此问题已提交的一些github问题:
https://github.com/rails/rails/issues/3903
https://github.com/rails/rails/issues/3085
显然有一个由has_many:通过关系引起的无证自动计数器缓存。因此,如果Teacher.has_many :students, :through => :classrooms
,那么teacher.students << student
集合分配已经查找,如果该列存在则会增加teacher.students_count
。
如果添加Classroom.belongs_to :teacher, :counter_cache => :students_count
,则会在创建“课堂”模型时触发其他回调,并且该列会增加两次。
有效解决方法:将计数器缓存列重命名为其他内容。 Student#teacherz_count
和Teacher#studentz_count
有效允许test case通过。
https://github.com/carlzulauf/test_app/commit/707a33f948d5d55a8aa942e825841fdd8a7e7705
我还没有找到问题在ActiveRecord代码库中的位置,所以我暂时不会接受我自己的答案,以防有人知道为什么has_many :through
以这种方式工作以及违规代码的存在。
我相信我发现了令人讨厌的代码行。注释掉这一行可以解决问题:
我似乎无法启动并运行边缘导轨,因此我无法提交此错误。如果其他人能够,请做。
查找违规行允许我在我的测试应用中制作更有效的猴子补丁,解决问题而无需重命名任何列。
https://github.com/carlzulauf/test_app/commit/3c421b035bd032b91ff60e3d74b957651c37c7fa