lee*_*our 1 postgresql activerecord ruby-on-rails jsonb
我想在 PostgreSQL 的 JSONB 列中存储对象数组。我正在使用 Rails 5.2。我使用自定义序列化程序来确保分配给 JSONB 字段的值是数组而不是哈希。当我向该字段分配类似内容时遇到错误[{a: 1}]
。这是代码:
模型:
class Printing
serialize :card_faces, CardFacesSerializer
end
Run Code Online (Sandbox Code Playgroud)
序列化器:
class CardFacesSerializer
include JSONBArraySerializer
def allowed_attributes
%i[name image]
end
end
Run Code Online (Sandbox Code Playgroud)
序列化器关注点:
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
Run Code Online (Sandbox Code Playgroud)
评估时:
pr = Printing.first
pr.card_faces = [{hay: 12}]
pr.save!
Run Code Online (Sandbox Code Playgroud)
我收到错误:
标准错误:预期的 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
Run Code Online (Sandbox Code Playgroud)
不要对 JSON/JSONB 列使用序列化。
请记住,数据库适配器会为您处理某些序列化任务。例如:PostgreSQL 中的 json 和 jsonb 类型将在 JSON 对象/数组语法和 Ruby Hash 或 Array 对象之间透明地转换。在这种情况下不需要使用序列化。 https://api.rubyonrails.org/classes/ActiveRecord/AttributeMethods/Serialization/ClassMethods.html
serialize
是一个旧的 hack,用于在字符串列中存储 JSON/YAML/任何内容。说真的 - 不要使用它。它只会导致双重转换的问题。
您正在做的事情应该由常规模型验证和/或自定义设置器来处理。
归档时间: |
|
查看次数: |
2581 次 |
最近记录: |