You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在类Facebook应用中避免ActiveRecord的UniqueViolation错误?

解决ActiveRecord::RecordNotUnique错误及权限验证问题

嗨,我来帮你搞定这两个头疼的问题:重复点击移除按钮触发的数据库唯一约束错误,还有权限验证逻辑失效导致的越权操作。

1. 先搞定重复创建隔离记录的错误

你现在的quarantine方法用了create!,这货不管三七二十一就往数据库插新记录,但你的表已经加了user_id + micropost_id的唯一索引,重复插肯定撞墙。

换成find_or_create_by!就完美解决了——它会先查有没有已经存在的隔离记录,有就直接返回,没有才创建新的,完全不会触发重复插入错误:

def quarantine
  current_user.micropost_quarantines.find_or_create_by!(micropost_id: @micropost.id)
  # 这里加个友好提示,用户体验更好
  redirect_to request.referer || root_url, notice: "这条动态已经从你的信息流里移除啦"
end

2. 修复权限验证的逻辑漏洞

你之前改的entitled_user逻辑有问题,unless里的|| @quarantine.nil?相当于说“只要已经隔离过,不管用户有没有权限都能继续操作”,这直接把你原本的权限限制给绕过去了,难怪能隔离非关注用户的动态。

正确的逻辑应该是:先验证用户有没有权限(要么是动态的发布者,要么关注了发布者),没权限直接踢走;有权限的话,再检查是不是已经隔离过,是的话就提示用户别重复操作:

def entitled_user
  @micropost = Micropost.find(params[:id])
  
  # 第一步:检查用户是否有权限操作这条动态
  has_permission = current_user == @micropost.user || current_user.following.exists?(@micropost.user.id)
  unless has_permission
    redirect_to root_url, alert: "你没权限操作这条动态哦"
    return
  end

  # 第二步:检查是不是已经隔离过了,避免重复操作
  if current_user.micropost_quarantines.exists?(micropost_id: @micropost.id)
    redirect_to request.referer || root_url, notice: "这条动态早就从你信息流里移除啦"
  end
end

这里顺便提个小优化:current_user.following.include?(@micropost.user)会把所有关注的用户都加载到内存里再判断,用户关注的人多了会很慢,换成current_user.following.exists?(@micropost.user.id)会直接生成SQL查询,效率高很多。

最后说一句

你给micropost_quarantines表加的唯一索引非常棒,这是数据库层面的最后一道防线,配合我们在应用层的判断,双重保障不会出现重复记录。

内容的提问来源于stack exchange,提问作者Asarluhi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:58:51