关于 ecto-constraint-debug
ecto-constraint-debug 是面向 Elixir 开发者的调试 Skill,用于排查 Ecto 约束错误。它从错误中的约束名称入手,检查迁移、Schema 处理和所有写入路径,并考虑竞态条件。
主要功能
- 01解析约束错误详情
- 02核对迁移与 Schema 约束
- 03追踪插入和更新路径
- 04排查可能的竞态条件
- 05按约束类型选择修复方式
适用场景
- 01诊断唯一约束冲突
- 02查找外键错误原因
- 03排查 Changeset 约束失败
- 04验证通过后检查并发写入问题
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ oliver-kriska/ claude-elixir-phoenix --skill ecto-constraint-debug安装后在 Claude Code 中输入/ecto-constraint-debug确认已加载。
附带文件references/constraint-patterns.md
详细介绍
Ecto 约束调试
Ash 项目:Ash 通过自己的错误 DSL 显示数据库约束。请使用
ash-framework技能——mix usage_rules.search_docs "constraint" -p ash_postgres。
系统地诊断约束违反问题。当遇到 Ecto.ConstraintError、unique_constraint、foreign_key_constraint 或与约束相关的 changeset 错误时,请加载此内容。
铁律
- 读取约束名称——约束名称(例如
links_url_index)会准确指出哪个索引或约束失败。首先从错误消息中解析名称 - 先检查迁移,再看代码——确认
priv/repo/migrations/中的约束定义与 schema 的预期一致 - 追踪所有插入路径——找出所有向受约束表插入数据的代码路径。错误往往出现在你没有考虑到的路径中
- 除非证实并非如此,否则先假定是竞态条件——如果验证通过但约束仍失败,就先假定是并发插入,直到证明是单个请求导致的
分步调试
步骤 1:解析错误
从错误消息中提取:
- 约束名称(例如
users_email_index) - 表名(例如
users) - 操作(插入、更新或删除)
- 冲突值(如果日志中有提供)
步骤 2:查找迁移
使用 Grep 在 priv/repo/migrations/ 中搜索约束名称。还要检查 create unique_index、create index 和 add constraint。
确认:迁移中的约束是否与 schema 中的 unique_constraint/3 或 foreign_key_constraint/3 调用一致?
步骤 3:查找 Schema
使用 Grep 在 lib/ 中查找 changeset 里的约束处理(unique_constraint、foreign_key_constraint、check_constraint)。
步骤 4:追踪插入路径
找出所有插入或更新此 schema 的调用方:
使用 Grep 在 lib/ 中查找所有插入或更新路径(Repo.insert、Repo.update、Repo.insert_all、cast_assoc)。
步骤 5:确定原因
| 症状 | 可能原因 | 修复模式 |
|---|---|---|
| 同一用户触发两次 | 竞态条件(双击、重试) | 使用 on_conflict 执行 Upsert |
| 多个父项共享同一个子项 | cast_assoc 不会跨 changeset 去重 | 构建 changeset 前先去重 |
| 并发 API 请求 | 缺少事务隔离 | 使用 Repo.transaction 包装操作,或使用 Upsert |
| 迁移对现有数据添加了约束 | 数据违反了新约束 | 先回填或清理数据 |
步骤 6:应用修复
详细修复模式请参见 ${CLAUDE_SKILL_DIR}/references/constraint-patterns.md。
按约束类型快速修复
唯一性违反 → 使用 Upsert:Repo.insert(changeset, on_conflict: :replace_all, conflict_target: [:field])
外键违反 → 检查:被引用的记录是否存在?它是否被并发删除?
检查约束 → 验证:该值是否满足约束条件?
参考资料
${CLAUDE_SKILL_DIR}/references/constraint-patterns.md- 各类约束的详细模式