我有三个模特
主题
class Subject < ActiveRecord::Base
has_many :enrollments, dependent: :destroy
has_many :students, through: :enrollments, source: :students
用户
class User < ActiveRecord::Base
has_many :enrollments, foreign_key: 'student_id', dependent: :destroy
has_many :subjects, through: :enrollments
注册
class Enrollment < ActiveRecord::Base
belongs_to :subject
belongs_to :student, class_name 'User'
让我说,首先我做
User.count # return 23
它返回23,这很好。但是如果我做的话
c = Subject.first # Any subject
s = c.students
s.size # It returns 1, so it does have AR, and I can see the users.
s.class # For some reason it is an Array, not an AR, but rails is probably lying
s.destroy_all # Shows it destroys it successfully
s # Returns []
c.students # Returns []
但问题是我打电话
User.count # It still return 23
计数错了。它应该是22.我仍然可以使用User.find(delete_student_id) 并仍然看到记录。当我使用Use.count时,它不是缓存问题,因为我使用User.all.size,它给出了23。
我希望学生实际上是从数据库中删除的,使用subject.students.destroy_all
现在我正在使用
User.where(id: s.pluck('users.id')).destroy_all
或
s.each do |student|
student.destroy
end
这些会起作用,但对我来说是一个很大的代码味道。
答案 0 :(得分:0)
您需要将Enrollment
类更新为依赖销毁用户:
class Enrollment < ActiveRecord::Base
belongs_to :subject
belongs_to :student, class_name 'User', dependent: :destroy
end
但是,我不建议这样做,因为只要User
注册多个Subjects
,它就会抛出错误。
如果您要删除任何未注册的User
,我会在after_destroy
上使用Enrollment
回调。
答案 1 :(得分:0)
destroy_all
确实仅在mikerz建议时删除了注册。我重新创建了你的设置并运行了rails console:
>> Subject.first.students.destroy_all
Subject Load (1.0ms) SELECT `subjects`.* FROM `subjects` LIMIT 1
User Load (0.0ms) SELECT `users`.* FROM `users` INNER JOIN `enrollments` ON `users`.`id` = `enrollments`.`student_id` WHERE `enrollments`.`subject_id` = 1
(0.0ms) BEGIN
Enrollment Load (0.0ms) SELECT `enrollments`.* FROM `enrollments` WHERE `enrollments`.`subject_id` = 1 AND `enrollments`.`student_id` = 1
SQL (22.0ms) DELETE FROM `enrollments` WHERE `enrollments`.`id` = 2
(91.0ms) COMMIT
[#<User id: 1, name: "a user", created_at: "2014-02-24 21:49:05", updated_at: "2014-02-24 21:49:05">]
因此,通过合同,返回已删除的对象,:through
关联似乎有点过时了。离开你
Subject.first.students.select.destroy_all
(其中select是切换到删除用户的魔力),
Subject.first.students.each { |student| student.destroy }
和
User.destroy_all(id: Subject.first.students.collect { |student| student.id })
由于有depent: :destroy
,这三个中的前两个似乎运行相同数量的SQL,而第三个将加载每个User
两次。
每个变体一次销毁一个注册和一个用户,而不是所有注册(甚至不是单个用户的注册)或一个语句中的所有用户。 destroy_all - API doc:
注意:当您一次删除多条记录时,实例化,回调执行和删除每条记录都会非常耗时。它为每条记录生成至少一个SQL DELETE查询(或者更多,以强制执行您的回调)。如果要快速删除多行,而不关心它们的关联或回调,请改用delete_all。