Devise Invitable 输入已存在邮箱误删关联HealthRecord问题排查
问题根源
从日志执行顺序可以定位到三个核心原因:
- 视图中调用的
setup_user(resource)如果会为用户执行build_health_record操作,对于已存在、且已经关联了HealthRecord的用户,调用has_one关联的build_xxx方法会将原有关联记录标记为待删除,保存时会直接删除旧关联 accepts_nested_attributes_for :health_record默认配置下,传入无ID的嵌套关联属性时,也会触发旧关联删除再新建的逻辑- devise_invitable默认的创建流程中,邮箱唯一性校验的执行时机晚于关联属性的保存操作,导致删除操作在校验报错前就已提交事务,不会被回滚
解决方案
步骤1:修改嵌套属性配置
在User模型中给嵌套属性配置添加update_only: true,避免传入无ID的嵌套属性时删除旧关联:
# 替换原有的accepts_nested_attributes_for配置 accepts_nested_attributes_for :health_record, update_only: true
该配置作用是:关联已存在时只会更新属性,不会删除旧记录再新建。
步骤2:修正setup_user方法逻辑
修改视图中调用的setup_user辅助方法,仅为未持久化的新用户初始化HealthRecord,避免给已存在的用户执行build操作:
def setup_user(user) # 只有新用户才需要初始化健康档案 user.build_health_record if user.new_record? && user.health_record.nil? user end
步骤3:邀请控制器前置拦截重复邮箱请求
重写邀请控制器的create方法,在处理参数前先校验邮箱是否存在,从根源避免后续关联操作执行:
class Users::InvitationsController < Devise::InvitationsController # 保留原有其他逻辑 def create # 前置校验邮箱唯一性 if User.exists?(email: params.dig(:user, :email)) self.resource = build_resource resource.errors.add(:email, :taken) render :new and return end super end end
内容的提问来源于stack exchange,提问作者lautar0
相关产品推荐
相关产品推荐

