Serialização de atributos do Active Record com classe personalizada

Quando estávamos portando nosso aplicativo antigo para uma nova pilha de ruby ​​mantendo o banco de dados subjacente intacto. Nós poderíamos usar o recurso de serialização de registro ativo do Rails bastante intensamente. Aqui está um exemplo simples –

Tínhamos um atributo de string “largura” que esperava um valor semelhante a “10 polegadas” ou “20 cm”.

Anteriormente, era preciso pegar manualmente duas entradas separadas, concatená-las e armazená-las em um único atributo de string.

Refizemos a mesma coisa, mas de uma maneira um pouco melhor usando a serialização ActiveRecord, aqui vai o código –

class SomeModel < ActiveRecord::Base
serialize
:width, ValueAndUnit
end

Classe Serializer que despeja e carrega os dados com base em nosso formato esperado –

class ValueAndUnit
attr_reader
:value, :unit

def initialize(value = nil, unit = nil)
@value, @unit = value, unit
end

class << self

# Load serialized data into the model scope with our expected transformation.
# ie. we expect successful execution could return ValueAndUnit instance from width method.
#
# @return [ValueAndUnit] The instance of ValueAndUnit from cleaned out string data.
def load(data)
# Make sure data is compliant with our expected data format
if data.present? && (matched_data = data.match(/([d.]+)s+(.+)/))
self.new(matched_data[1], matched_data[2])
else
self.new
end
end

# Dump the ValueAndUnit instance into the storable (serialized) format. In our case we want it to be stored as "{value} {unit}" ie. "10 Inches".
#
# @return [String] The transformed string representation of the data.
def dump(data)
data
.to_s
end
end

def to_s
"#{self.value} #{self.unit}"
end
end

Aqui vão alguns exemplos de uso –

record = SomeModel.new
record
.width.unit = 'Inches'
record
.width.value = 10
record
.save

Enquanto puxamos um recorde existente

record = SomeModel.find(1)
puts record
.width.unit # => 'Inches'
puts record
.width.value # => '10