ActiveRecord 错误地转义 JSON 字符串

问题描述 投票:0回答:1

我的 Rails 6.1.1 应用程序中的

jsonb
模型有一个名为“有效负载”的
Tweet
类型列。我使用 store 直接访问此属性上的各个字段:

class Tweet < ApplicationRecord
  store :payload, accessors: [:lang, :text, :entities], coder: JSON
end

(请注意,将序列化从 YAML 默认值更改为 JSON 需要

coder: JSON
部分 - 否则您最终会在
jsonb
列中看到 YAML。)

当我创建新推文时,我发现 ActiveRecord 在插入过程中错误地转义了 JSON 字符串:

Tweet.create payload: {foo: 'bar'}

TRANSACTION (0.7ms)  BEGIN
  Tweet Create (2.0ms)  INSERT INTO "tweets" ("payload", ...) VALUES ($1, ...) RETURNING "id"  [["payload", "\"{\\\"foo\\\":\\\"bar\\\"}\""], ...]

我指的是

"\"{\\\"foo\\\":\\\"bar\\\"}\""
部分。看起来已经被双重逃脱了。这会导致一种“stringception”,其中字符串中的字符串存储在
payloads
列中,使得 postgres 无法使用箭头
->
语法对字段执行任何搜索。 Postgres 无法将此值识别为 JSON。 (然而,看似奇迹般的是,Rails 能够在读取操作时正确反序列化该字段。)

另一位 SO 用户已说明此处的问题:https://dbfiddle.uk/gcwTQOUm

ruby-on-rails activerecord
1个回答
4
投票

当我使用

store
时,我无法重现该问题:

Tweet.create payload: {foo: 'bar'}
  TRANSACTION (0.2ms)  BEGIN
  Tweet Create (1.6ms)  INSERT INTO "tweets" ("payload", ...) VALUES ($1, ...) RETURNING "id"  [["payload", "{\"foo\":\"bar\"}"], ...]

"{\"foo\":\"bar\"}"
是所需的字符串。

这让我相信我使用

store
是错误的。

我检查了文档

注意:如果您使用结构化数据库数据类型(例如 PostgreSQL

hstore
/
json
或 MySQL 5.7+
json
),则不需要 .store 提供的序列化。只需使用 .store_accessor 来生成访问器方法。请注意,这些列使用字符串键控哈希,并且不允许使用符号进行访问。

换句话说,因为我已经使用了

jsonb
类型的列,Rails 已经知道要序列化哈希 - 应用另一个序列化会导致双重转义。

所以,不要这样做:

store :payload, accessors: [:lang, :text, :entities], coder: JSON

我现在做的是:

store_accessor :payload, :lang, :text, :entities

而且它有效。

© www.soinside.com 2019 - 2024. All rights reserved.