after_create触发无限SQL INSERT循环问题求助
解决Friendship模型反向关系创建的无限循环问题
嘿,我一眼就看出问题所在了——你的after_create回调直接陷入了无限循环!让我给你拆解原因和修复方案:
问题根源
当你创建一个Friendship记录时,after_create :create_inverse_relationship会触发,这个方法会给对方用户创建一个反向的Friendship。但问题来了:这个新创建的反向Friendship也会触发自己的after_create回调,它又会试图创建一个和最初完全一样的Friendship,如此往复,直到服务器栈溢出(就是你看到的SystemStackError (stack level too deep))。
从你的日志里也能看出来,系统一直在重复插入user_id:1, friend_id:3和user_id:3, friend_id:1的记录,完全停不下来。
修复方案
我们需要在创建反向关系时,临时跳过回调,同时增加存在性检查避免重复创建。下面是修改后的Friendship模型代码:
class Friendship < ApplicationRecord after_create :create_inverse_relationship after_destroy :destroy_inverse_relationship belongs_to :user belongs_to :friend, class_name: 'User' private def create_inverse_relationship # 先检查反向关系是否已存在,避免重复创建 return if friend.friendships.exists?(friend: user) # 临时禁用after_create回调,防止循环触发 Friendship.skip_callback(:create, :after, :create_inverse_relationship) do friend.friendships.create(friend: user) end end def destroy_inverse_relationship # 使用Ruby安全导航操作符,简化nil判断 friend.friendships.find_by(friend: user)&.destroy end end
修改点说明
- 存在性检查:在创建反向关系前先确认关系是否已存在,避免不必要的数据库操作和重复记录。
- 临时跳过回调:用
skip_callback包裹创建操作,让反向Friendship的创建过程不触发after_create,彻底斩断循环链条。 - 简化销毁逻辑:用
&.安全导航操作符替代if判断,代码更简洁健壮。
备选方案:手动创建双向关系(更可控)
如果你不想依赖回调的隐式行为,也可以直接在FriendRequest的accept方法里手动创建双向关系,完全移除Friendship的after_create回调:
# FriendRequest模型的accept方法修改 def accept # 直接创建双向好友关系 user.friendships.create(friend: friend) friend.friendships.create(friend: user) destroy end
这种方式逻辑更直观,减少了回调带来的隐式依赖,适合喜欢清晰控制流程的场景。
内容的提问来源于stack exchange,提问作者tfantina
相关产品推荐
相关产品推荐

