使用 Rails 5 在 Postgres 中存储字符串化 JSON

Posted

技术标签:

【中文标题】使用 Rails 5 在 Postgres 中存储字符串化 JSON【英文标题】:Storing Stringified JSON in Postgres with Rails 5 【发布时间】:2017-07-23 04:11:32 【问题描述】:

我们正在将我们的应用程序从 Rails 4.2 升级到 Rails 5.0。

我们发现相同的请求在插入数据库时​​会生成不同的 sql。数据库列是 JSON,看起来在 Rails 5.0 中它被存储为转义字符串。

有谁知道我们如何确保版本之间的行为相同?

请求参数:

参数:"provider_package_item"=>"provider_package_id"=>"2", "service_id"=>"6", "service_product_id"=>"17", "provider_price_list_id"=>"12", "provider_price_list_item_id "=>"122", "options"=>"[\"id\":95,\"title\":\"Finish\",\"value\":\"id\":\" 130\",\"title\":\"Satin\",\"price\":0,\"id\":96,\"title\":\"纸张重量\",\"价值\":\"id\":\"135\",\"title\":\"200GSM\",\"price\":0,\"id\":112,\" title\":\"Delivery\",\"value\":\"id\":\"189\",\"title\":\"Next Day\",\"price\":0 ]"

Rails 4.2 中的数据库查询:

插入“provider_package_items”(“provider_package_id”、“service_id”、“service_product_id”、“provider_price_list_id”、“provider_price_list_item_id”、“options”、“title”、“quantity”、“price”、“options_string”、“ created_at", "updated_at") 值 ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) 返回 "id" [["provider_package_id", 2], ["service_id" , 6], ["service_product_id", 17], ["provider_price_list_id", 12], ["provider_price_list_item_id", 122], ["options", "[\"id\":95,\"title\": \"Finish\",\"value\":\"id\":\"130\",\"title\":\"Satin\",\"price\":0,\" id\":96,\"title\":\"纸张重量\",\"value\":\"id\":\"135\",\"title\":\"200GSM\", \"price\":0,\"id\":112,\"title\":\"Delivery\",\"value\":\"id\":\"189\", \"title\":\"Next Day\",\"price\":0]"], ["title", "A4 Brochures"], ["quantity", 50], ["price", 65.0], ["options_string", "/Satin/200GSM/Next Day"], ["created_at", "2017-03-03 05:36:51.613297"], ["updated_at", "2017-03-03 05 :36:51.613297"]]

Rails 5.0 中的数据库查询

插入“provider_package_items”(“title”、“service_id”、“service_product_id”、“provider_price_list_id”、“provider_price_list_item_id”、“quantity”、“options”、“options_string”、“created_at”、“updated_at”、“ provider_package_id", "price") 值 ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) 返回 "id" [["title", "A4 Brochures"], [ "service_id", 6], ["service_product_id", 17], ["provider_price_list_id", 12], ["provider_price_list_item_id", 122], ["quantity", 50], ["options", "\"[\ \"id\\":95,\\"title\\":\\"完成\\",\\"值\\":\\"id\\":\\"130\\", \\"title\\":\\"缎面\\",\\"price\\":0,\\"id\\":96,\\"title\\":\\"纸张重量\\",\\"值\\":\\"id\\":\\"135\\",\\"title\\":\\"200GSM\\",\\" price\\":0,\\"id\\":112,\\"title\\":\\"Delivery\\",\\"value\\":\\"id\ \":\\"189\\",\\"title\\":\\"第二天\\",\\"price\\":0]\""], ["options_string", "/Satin/200GSM/Next Day"], ["created_at", 2017-03-03 05:30:02 UTC], ["updated_at", 2017-03-03 05:30:02 UTC], ["provider_package_id ", 2 ], [“价格”, 65.0]]

【问题讨论】:

【参考方案1】:

Rails 5 已更新为符合 RFC 7159。JSON 字符串,例如javascript 中的 JSON.stringify() 现在保存为字符串而不是哈希/数组。要保持以前版本的 Rails 的行为,您需要在分配之前解析 JSON 字符串:

Model.payload = JSON.parse("\"key\":\"value\"")

或者你可以覆盖模型中的setter方法:

def payload=(value)
  self[:payload] = value.is_a?(String) ? JSON.parse(value) : value
end

【讨论】:

【参考方案2】:

在https://github.com/rails/rails/issues/28292

kengreeff 的观察

在控制台中(Rails 4.2.2)

item = OrderItem.new(options: "\"key\":\"value\"")
 => #<OrderItem id: nil, options: "key"=>"value">

item.options
 => "key"=>"value" 

item.options.is_a?(String)
 => false 

item.options.is_a?(Hash)
 => true

在控制台中(Rails 5.0.2)

item = OrderItem.new(options: "\"key\":\"value\"")
 => #<OrderItem id: nil, options: "\"key\":\"value\"">

item.options
 => "\"key\":\"value\""

item.options.is_a?(String)
 => true 

item.options.is_a?(Hash)
 => false

kamipo 提到过这个

导轨 5

这种行为是因为efaa6e4 修复了问题#24234。 请使用

OrderItem.new(options: JSON.parse("\"key\":\"value\"")).

【讨论】:

以上是关于使用 Rails 5 在 Postgres 中存储字符串化 JSON的主要内容,如果未能解决你的问题,请参考以下文章

Postgres / Rails Active Record - 查询四舍五入的浮点值

如何将 Postgres 数据库从一个 Elastic Beanstalk 环境复制到另一个环境?我正在使用 Rails 5

如何在 Rails 3 的 Postgres 数据库中使用枚举? [关闭]

Postgres 13.2 on rails 5.2.4.1: ActiveRecord::NoDatabaseError: FATAL: database * does not exist on r

使用 Activerecord、Rails 和 Postgres 查找具有多个重复字段的行

在 Rails 和 PostgreSQL 中完全忽略时区