ruby-on-rails - 在 Rails JSONB 列中使用数组
问题描述
我想在 PostgreSQL 的 JSONB 列中存储一个对象数组。我正在使用 Rails 5.2。我正在使用自定义序列化程序,以确保分配给 JSONB 字段的值是数组而不是哈希。[{a: 1}]
在为该字段分配类似内容时出现错误。这是代码:
模型:
class Printing
serialize :card_faces, CardFacesSerializer
end
序列化器:
class CardFacesSerializer
include JSONBArraySerializer
def allowed_attributes
%i[name image]
end
end
序列化程序关注:
module JSONBArraySerializer
extend ActiveSupport::Concern
def initialize(data)
return [] if data.blank?
if data.is_a?(String)
json = Oj.load(data, symbol_keys: true)
end
raise ArgumentError, "#{json} must be [{},{}], not {}" if json.is_a?(Hash)
# Will only set the properties that are allowed
json.map do |hash|
hash.slice(self.allowed_attributes)
end
end
class_methods do
def load(json)
return [] if json.blank?
self.new(json)
end
def dump(obj)
# Make sure the type is right.
if obj.is_a?(self)
obj.to_json
else
raise StandardError, "Expected #{self}, got #{obj.class}"
end
end
end
end
评估时:
pr = Printing.first
pr.card_faces = [{hay: 12}]
pr.save!
我收到一个错误:
标准错误:预期 CardFacesSerializer,得到数组
我不认为转储/加载是如何工作的。为什么dump
在保存期间被调用?如何修复我的代码以正常工作?
更新
我设法使它与这个序列化程序关注的代码一起工作:
module JSONBArraySerializer
extend ActiveSupport::Concern
class_methods do
def load(data)
return [] if data.blank?
if data.is_a?(String)
json = Oj.load(data, symbol_keys: true)
end
raise ArgumentError, "#{json} must be [{},{}], not {}" if json.is_a?(Hash)
# Will only set the properties that are allowed
json.map do |hash|
hash.slice(*allowed_attributes)
end
end
def dump(obj)
# Make sure the type is right.
if obj.is_a?(Array)
obj.to_json
else
raise ArgumentError, "Expected Array, got #{obj.class}"
end
end
end
end
解决方案
不要对 JSON/JSONB 列使用序列化。
请记住,数据库适配器会为您处理某些序列化任务。例如:PostgreSQL 中的 json 和 jsonb 类型将在 JSON 对象/数组语法和 Ruby Hash 或 Array 对象之间透明地转换。在这种情况下不需要使用序列化。 https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Serialization/ClassMethods.html
serialize
是一种旧的 hack,用于在字符串列中存储 JSON/YAML/任何内容。说真的 - 不要使用它。它只会导致双重转换的问题。
您正在做的事情应该由常规模型验证和/或自定义设置器处理。
推荐阅读
- javascript - 如何将新对象添加到模型中对象的属性
- javascript - 缺少 CORS 400 标头(以及其他问题)
- javascript - 如何在 Svelte 中绑定子组件的输入值?
- c - c fscanf 存储字符串
- python - 如何从其他集合中存在的值中删除包含模式的python集合中的字段
- node.js - actions-on-google 帐户链接登录状态始终为“错误”
- vpn - 大纲管理器,防火墙规则正在阻止传入连接
- performance - 完成一项非常庞大且重复性的任务的最佳方法是什么?
- php - 将字符串从文件加载到html中?最好不要使用javascript
- clojure - EDN中'$ % &'之类的符号有什么用?