Rails中Choice对象创建失败排查:关联模型后数据未入库
哦,这种情况我太熟了!之前在Rails项目里也碰到过好几次,创建对象后用Choice.last查不到,大概率是下面这些原因,咱们一步步排查:
验证失败,对象根本没存进数据库
很多时候你以为创建成功了,但其实模型的验证规则把它拦下来了。比如Choice关联了Question,你可能没传question_id,或者某个必填字段为空,或者格式不符合要求。
排查方法很简单:用带感叹号的创建方法,失败会直接抛出异常告诉你哪里错了:# 用create!代替create,失败就报错 Choice.create!(question: your_question_instance, content: "测试选项")或者创建后手动检查错误信息:
choice = Choice.new(question: your_question_instance, content: "") choice.save # 这里会返回false puts choice.errors.full_messages # 打印所有验证失败的原因事务回滚了
如果你的创建代码是放在事务块里的,比如:ActiveRecord::Base.transaction do Choice.create(...) # 这里如果有其他操作抛出异常,整个事务会回滚 raise "出问题了" end哪怕Choice创建成功了,只要事务里有异常导致回滚,数据库里就不会有这条记录。检查一下你的代码是不是包裹在事务中,有没有隐性的异常触发回滚。
关联的Question对象还没持久化
因为Choice和Question是关联的,如果你创建Choice时用的是一个还没保存到数据库的Question对象,比如:question = Question.new(title: "新问题") # 还没save Choice.create(question: question, content: "选项")这时候如果你的Choice模型有
validates :question, presence: true的验证,或者belongs_to :question默认开启了optional: false(Rails 5+默认),那这个Choice会因为关联的Question不存在而创建失败。
正确的做法是先保存Question,或者用关联的创建方法自动保存关联对象:# 方法1:先存Question question = Question.create!(title: "新问题") Choice.create!(question: question, content: "选项") # 方法2:用关联的create方法,自动保存Question(如果它是新记录) question = Question.new(title: "新问题") question.choices.create!(content: "选项")环境搞错了
比如你在RAILS_ENV=test的控制台里创建了对象,但之后去开发环境的数据库里查,那肯定找不到。先确认当前控制台的环境:puts Rails.env # 看是development还是test或者其他不同环境的数据库是分开的,别搞混了!
控制台缓存或查询范围问题
有时候控制台可能会有查询缓存?不过Choice.last一般会直接查数据库,但如果你的模型有默认作用域(比如default_scope { where(active: true) }),那Choice.last只会返回符合默认作用域的记录,如果你创建的Choice不符合,就查不到。试试用Choice.unscoped.last绕过默认作用域看看。
先从验证和事务这两个最常见的情况查起,基本上就能找到问题啦!
内容的提问来源于stack exchange,提问作者user3576036

