gpt4 book ai didi

mysql - 更新collection_singular_ids时如何触发 `dependent: destroy`

转载 作者:行者123 更新时间:2023-11-30 21:54:06 25 4
gpt4 key购买 nike

考虑以下设置:

class Task
has_many :users, through: :task_users
end

class User
has_many :tasks, through: :tasks_users
end

class TaskUser
# Joins table
has_many :comments, dependent: :destroy
end

class Comment
belongs_to :task_user
end

现在,如果我执行标准的 #destroy 命令,例如:

tu = TaskUser.first
tu.destroy

然后所有与任务用户关联的评论也将被销毁。

但是,假设您想通过 #collection_singular_ids= 更新用户的任务,像这样:

u = User.first
puts u.task_ids # => [1, 2, 3]
u.task_ids = [1, 2]

这样做(甚至不用显式调用 #save!)将触发 SQL,如下所示:

(0.3ms)  BEGIN
SQL (0.4ms) DELETE FROM `task_users` WHERE `task_users`.`task_id` = 3 AND `task_users`.`user_id` = 1
(2.0ms) COMMIT

...所以相关联的评论被孤立了。

如果您使用 #attributes= 会出现同样的问题:

u.attributes = { task_ids: [1, 2] }

是否有一种干净的方法来确保关联的 Comment 始终被销毁(即永远不会孤立)?

最佳答案

感谢@engineersmnky 为我指明了正确的方向。

这可能不是最好的解决方案,但一个可行的选择是 define a callback on the association ,例如:

class User
has_many :tasks,
through: :tasks_users,
before_remove: ->(user, task) do
task_user = TaskUser.find_by!(user: user, task: task)
task_user.comments.each(&:destroy!)
end

# Or alternatively, this can be defined as a method:

has_many :tasks,
through: :tasks_users,
before_remove: :destroy_task_user_comments

private

def destroy_task_user_comments(task)
task_user = TaskUser.find_by!(user: self, task: task)
task_user.comments.each(&:destroy!)
end
end

请注意,我在 block 中使用了 bang (!) 方法,以便在引发异常时整个事务将回滚 - 根据文档:

if any of the before_remove callbacks throw an exception, the object will not be removed from the collection.

关于mysql - 更新collection_singular_ids时如何触发 `dependent: destroy`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45986614/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com