实例公共方法
serialize(attr_name, coder: nil, type: Object, comparable: false, yaml: {}, **options) 链接
如果您有一个需要被序列化为对象并保存到数据库,然后反序列化回同一个对象以供检索的属性,请使用此方法指定该属性的名称,序列化将自动处理。
序列化格式可以是 YAML、JSON,或者使用自定义编码器类的任何自定义格式。
请注意,数据库适配器会为您处理某些序列化任务。例如:PostgreSQL 中的 json 和 jsonb 类型将在 JSON 对象/数组语法和 Ruby 的 Hash 或 Array 对象之间透明地转换。在这种情况下,无需使用 serialize。
对于更复杂的情况,例如与应用程序域对象之间的转换,请考虑使用 ActiveRecord::Attributes API。
参数¶ ↑
-
attr_name- 要序列化的属性名称。 -
coder使用的序列化器实现,例如JSON。-
属性值将使用编码器的
dump(value)方法进行序列化,并使用编码器的load(string)方法进行反序列化。dump方法可以返回nil以将值序列化为NULL。
-
-
type- 可选。序列化对象的类型应为何种类型。-
尝试序列化其他类型将引发
ActiveRecord::SerializationTypeMismatch错误。 -
如果列为
NULL或从新记录开始,默认值将设置为type.new
-
-
comparable- 指定反序列化的对象是否可安全比较以检测更改。默认为false。当设置为false时,旧值和新值将根据它们的序列化表示(例如 JSON 或 YAML)进行比较,这有时会导致语义上相等的两个对象被视为不同。例如,两个具有相同键值但顺序不同的哈希具有不同的序列化表示,但在反序列化后是语义相等的。如果设置为true,则将在反序列化对象上进行比较。此选项仅在type已知具有正确的==方法可以深度比较对象时才应启用。 -
yaml- 可选。YAML 特定选项。允许的配置是-
:permitted_classes- 允许的类列表(Array)。 -
:unsafe_load- 不安全地加载 YAML 块,允许 YAML 加载任何类。
-
选项¶ ↑
-
:default- 未提供值时使用的默认值。如果未传递此选项,将使用之前的默认值(如果存在)。否则,默认为nil。
选择序列化器¶ ↑
虽然可以使用任何序列化格式,但建议在使用前仔细评估序列化器的属性,因为之后迁移到另一种格式可能会很困难。
避免接受任意类型¶ ↑
在序列化列中的数据时,强烈建议确保只序列化预期的类型。例如,某些序列化器(如 Marshal 或 YAML)能够序列化几乎任何 Ruby 对象。
这可能导致序列化意外的类型,并且类型序列化在某些数据库记录仍包含这些序列化类型的情况下,保持向后和向前兼容性非常重要。
class Address def initialize(line, city, country) @line, @city, @country = line, city, country end end
在上面的示例中,如果 Address 的任何属性被重命名,在更改之前持久化的实例将以旧属性加载。当序列化类型来自不期望以这种方式序列化的依赖项,并且可能在未通知的情况下更改其内部表示时,这个问题会变得更糟。
因此,强烈建议而是将这些对象转换为序列化格式的原始类型,例如
class Address attr_reader :line, :city, :country def self.load(payload) data = YAML.safe_load(payload) new(data["line"], data["city"], data["country"]) end def self.dump(address) YAML.safe_dump( "line" => address.line, "city" => address.city, "country" => address.country, ) end def initialize(line, city, country) @line, @city, @country = line, city, country end end class User < ActiveRecord::Base serialize :address, coder: Address end
此模式允许更谨慎地控制序列化的内容,并以向后兼容的方式演进格式。
确保序列化稳定性¶ ↑
某些序列化方法可能会通过静默地将它们转换为其他类型来接受它们不支持的某些类型。这在数据反序列化时可能导致错误。
例如,标准库中提供的 JSON 序列化器会将不受支持的类型静默转换为 String。
>> JSON.parse(JSON.dump(Struct.new(:foo))) # => "#<Class:0x000000013090b4c0>"
示例¶ ↑
使用 YAML 序列化 preferences 属性¶ ↑
class User < ActiveRecord::Base serialize :preferences, coder: YAML end
使用 JSON 序列化 preferences 属性¶ ↑
class User < ActiveRecord::Base serialize :preferences, coder: JSON end
使用 YAML 序列化 preferences Hash¶ ↑
class User < ActiveRecord::Base serialize :preferences, type: Hash, coder: YAML end
使用 YAML 序列化 preferences,并允许选择的类¶ ↑
class User < ActiveRecord::Base serialize :preferences, coder: YAML, yaml: { permitted_classes: [Symbol, Time] } end
使用自定义编码器序列化 preferences 属性¶ ↑
class Rot13JSON def self.rot13(string) string.tr("a-zA-Z", "n-za-mN-ZA-M") end # Serializes an attribute value to a string that will be stored in the database. def self.dump(value) rot13(ActiveSupport::JSON.dump(value)) end # Deserializes a string from the database to an attribute value. def self.load(string) ActiveSupport::JSON.load(rot13(string)) end end class User < ActiveRecord::Base serialize :preferences, coder: Rot13JSON end
来源: 显示 | 在 GitHub 上
# File activerecord/lib/active_record/attribute_methods/serialization.rb, line 193 def serialize(attr_name, coder: nil, type: Object, comparable: false, yaml: {}, **options) coder ||= default_column_serializer unless coder raise ArgumentError, <<~MSG.squish missing keyword: :coder If no default coder is configured, a coder must be provided to `serialize`. MSG end column_serializer = build_column_serializer(attr_name, coder, type, yaml) attribute(attr_name, **options) decorate_attributes([attr_name]) do |attr_name, cast_type| if type_incompatible_with_serialize?(cast_type, coder, type) raise ColumnNotSerializableError.new(attr_name, cast_type) end cast_type = cast_type.subtype if Type::Serialized === cast_type Type::Serialized.new(cast_type, column_serializer, comparable: comparable) end end