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

如何在Rails中使用update_all更新ActiveRecord store属性?

Rails中用update_all批量更新ActiveRecord Store属性的方案

我们在Rails模型里通过ActiveRecord的store来存储结构化配置:

store :settings, accessors: %i[enabled unit_of_distance], coder: JSON

这让我们能像访问普通数据库列一样操作这些属性:

Model.first.enabled => true
Model.first.unit_of_distance => 'miles'

但直接用update_all批量更新store属性时会报错:

Model.update_all(unit_of_distance: 'miles')

错误信息:

ActiveRecord::StatementInvalid: Mysql2::Error: Unknown column 'model.unit_of_distance' in 'field list'

如果给属性加上settings前缀,虽然不会报错,但会覆盖整个settings字段里的其他属性,这不是我们想要的:

Model.update_all(settings: { unit_of_distance: 'miles' })

手动循环更新是可行的,但效率极低:

Model.all.each { |c| c.update(unit_of_distance: 'miles') }

高效解决方案:利用数据库JSON函数实现批量更新

不用循环,直接通过update_all结合数据库的JSON操作函数,就能只更新store里的指定属性,同时保留其他字段内容。

针对MySQL/MariaDB

使用JSON_SET函数,直接在update_all中写入SQL片段:

Model.update_all("settings = JSON_SET(settings, '$.unit_of_distance', 'miles')")

JSON_SET会仅更新指定路径的键值对,不会覆盖整个settings字段。

针对PostgreSQL

如果settings是jsonb类型(推荐使用该类型),使用jsonb_set:

Model.update_all("settings = jsonb_set(settings, '{unit_of_distance}', '\"miles\"'::jsonb)")

如果是json类型,用json_set:

Model.update_all("settings = json_set(settings, '{unit_of_distance}', '\"miles\"'::json)")

这里需要把字符串值转成JSON格式,所以用'\"miles\"',路径用'{unit_of_distance}'指定。

这种方式直接在数据库层面执行批量更新,和update_all的原生效率一致,无需加载所有模型实例,完美解决循环更新的性能问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 20:07:19