Rails存储params到text列后JSON.parse报unexpected token错误
问题根因
这个问题和字段是text还是jsonb没有关系。
你存入字段的内容是Ruby哈希对象的原生字符串表示,不是标准JSON格式:存储内容里键值对用Ruby特有的哈希火箭=>分隔,而标准JSON要求键值对用冒号:分隔,格式不符合JSON规范,自然无法用JSON.parse解析。
哪怕你把字段改成jsonb类型,直接传入ActionController::Parameters对象存储,依然会出现序列化格式错误,甚至会直接触发数据库的JSON格式校验报错。
无需修改字段类型的解决方案
不需要做数据库迁移,只要在参数序列化和模型读取逻辑上做调整即可:
- 存储时主动将参数转为标准JSON格式
不要直接把ActionController::Parameters对象赋值给metadata字段,先过滤掉Rails自动注入的controller、action等冗余参数,转成普通哈希后再序列化为标准JSON字符串存储,修改后的控制器代码示例:class NotificationsController < ApplicationController def create # 按需permit你需要接收的Webhook字段,过滤冗余参数 valid_params = params.permit(:SmsSid, :SmsStatus).to_h notification = Notification.new( metadata: valid_params.to_json ) if notification.save head :ok end end end - 配置模型自动序列化,简化读写逻辑
在Notification模型中添加serialize配置,Rails会自动完成字段的JSON序列化/反序列化:赋值时自动把哈希转成标准JSON字符串存入text字段,读取时自动把字符串转回Ruby哈希,不需要手动调用to_json或JSON.parse,读写体验和jsonb字段基本一致:
配置完成后可以进一步简化控制器代码,直接传转好的哈希对象给class Notification < ApplicationRecord serialize :metadata, JSON endmetadata字段即可,序列化逻辑会由Rails自动处理。
历史存量数据处理
之前已经存入的旧数据是Ruby哈希格式字符串,无法直接被JSON解析,需要写一次性脚本做批量转换:
注意:如果存量数据来源不可信,禁止直接使用
eval做解析,避免恶意代码执行,建议使用安全的Ruby语法解析工具处理。如果确认所有数据都是自己系统生成的可信内容,可以参考如下逻辑处理:Notification.find_each do |notification| # 跳过已经是标准JSON格式的新数据 next if JSON.parse(notification.metadata) rescue false # 转换旧格式数据 old_hash = eval(notification.metadata) notification.update!(metadata: old_hash) end
内容的提问来源于stack exchange,提问作者pinkfloyd90
相关产品推荐
相关产品推荐

