Yii2更新失败却无报错,因新字段未在rules中声明safe或未纳入scenarios白名单,导致attributes赋值时被静默过滤,save()返回true但数据库未更新。

更新失败却没报错?先看字段是否在 safe 列表里
Yii2 的 save() 默认只保存 safe 属性,哪怕你手动赋值了新字段,只要它没出现在 rules() 里(或没被显式标记为 safe),就会被静默过滤掉。常见现象是:调用 $model->save() 返回 true,$model->errors 为空,但数据库里字段值根本没变。
解决方法很简单:
- 在
rules()中加一条['new_field', 'safe']规则(最常用) - 或者把新字段加进对应场景的
scenarios()白名单里,比如'update' => ['name', 'email', 'new_field'] - 若只是临时绕过验证,可用
$model->save(false),但注意:这不解决字段被过滤的问题——save(false)只跳过验证,不恢复非 safe 字段的写入权限
用 attributes = $data 赋值时 rules 失效的真相
当代码里写 $model->attributes = $data,Yii 会按 scenarios() 和当前 scenario 过滤 $data 键名,只保留“该场景允许加载”的字段。如果新字段不在白名单里,哪怕 $data 里有它,也会被丢弃——后续 save() 自然存不进去。
典型错误链:
- 数据库加了
utime字段,模型类没更新scenarios() - 控制器里写
$model->attributes = $data,其中$data['utime'] = time() -
$model->save()成功,但utime没入库
修复方式:要么补全 scenarios(),要么改用逐个赋值($model->utime = $data['utime']),后者不走字段白名单校验。
JSON 请求更新数据时 rules 不触发?load() 没跑成功
Yii 默认不解析 application/json 请求体,$request->post() 拿不到数据,$model->load($request->post()) 必然返回 false。但很多人忽略返回值,直接 validate(),结果验证永远“通过”,因为没数据可验。
正确流程必须包含三步:
$raw = $request->getRawBody()$data = \yii\helpers\Json::decode($raw)-
$model->load($data, '')—— 第二个参数传空字符串,否则默认前缀匹配失败
漏掉任意一步,rules 都不会真正参与校验和字段加载。
动态加规则后 update 仍失败?validator 生命周期被忽略
addRule() 添加的规则只对当前模型实例有效,且必须在 load() 之前调用,否则 load() 会重置属性但不会重建验证器列表。更关键的是:ActiveRecord 用 findOne() 加载的实例,其 validators 属性初始为空,addRule() 才能生效;而 new 出来的空模型,validators 已含 rules() 定义的规则,addRule() 是追加。
所以别在 beforeValidate() 里反复 addRule(),容易重复注册;也别指望 findOne() 后临时加规则就能覆盖原有逻辑——得先确保 scenarios() 和 rules() 本身已支持该字段。
最稳妥的做法,是把字段定义、规则声明、场景白名单三者同步维护,而不是靠运行时修补。否则每次加字段,都得检查这三处是否一致。


















