Rails为何无法将新的模型实例正常保存到数据库?
问题根因
你在控制台测试时出现的pn.slug返回赋值字符串,但pn对象inspect结果显示slug: nil,是*attr_accessor覆盖ActiveRecord原生属性方法*的典型特征:
如果你在app/models/page.rb中手动定义了和数据库字段重名的访问器(比如attr_accessor :slug、attr_accessor :title),会直接覆盖ActiveRecord自动生成的属性读写逻辑:
- 赋值时只会写入Ruby对象的实例变量,不会同步到ActiveRecord的属性集合,保存时不会把对应值提交到数据库
- 解决方法:直接删除模型中和数据库字段重名的
attr_accessor定义即可
其他代码问题修正
旧控制器的参数取值错误
Rails表单默认会把字段参数包裹在模型对应的命名空间下,你直接取params[:title]是取不到的,正确的取值路径是params[:page][:title],你后续更新的强参数写法已经解决了这个问题,只要删除模型多余的attr_accessor就能正常赋值。查询逻辑错误
你当前show、edit动作中使用where方法查询,返回的是集合而非单个对象,会导致后续调用出错,建议改为find_by!:
def show @page = Page.find_by!(slug: params[:slug]) end def edit @page = Page.find_by!(slug: params[:slug]) end
find_by!在找不到对应记录时会自动抛出404错误,不需要手动判断空值。
- 逻辑层级优化
slug生成逻辑不建议写在控制器中,放到模型回调里更合理,同时Rails自带parameterize方法可以直接生成符合URL规范的slug,不需要自定义helper实现:
class Page < ApplicationRecord # 务必删除和数据库字段重名的attr_accessor定义 before_validation :generate_slug, on: :create private def generate_slug self.slug = title.parameterize if title.present? end end
- 不要用空
rescue吞异常
空的rescue会吞掉所有错误信息,导致问题排查难度大幅提升,Rails的save方法本身会返回布尔值标识是否保存成功,你后续更新的if @page.save写法是正确的,不需要用begin rescue包裹。
内容的提问来源于stack exchange,提问作者von spotz
相关产品推荐
相关产品推荐

