[フレーム]
Last Updated: February 25, 2016
·
3.654K
· we4tech

Active Record Attribute Serialization with Custom Class

When we were porting our old application to a brand new ruby stack keeping the underlying database intact. We could use rails active record serialization feature quite intensely. Here is a simple example -

We had a string attribute "width" which was expecting value something like this "10 Inches" or "20 Cm".

Previously it was manually taking two separate inputs and concatenating them together and store them in a single string attribute.

We have remade the same thing but in bit better way using ActiveRecord serialization, here goes the code -

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

Serializer class which dumps and loads the data based on our expected format -

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

Here goes few sample usages -

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

While we are pulling an existing record

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

AltStyle によって変換されたページ (->オリジナル) /