2021-07-12 Rails composed_of を使ったValue Object パターン
Rails で Value Object パターンを扱うのに便利な composed_ofについて調べた。
オプション
class_name
: Value Objectの名前。Value Object生成時にこのクラスが使われるmapping
: ActiveRecord Object <=> Value Object の相互変換に使われるattributeのマッピング。複数の値をValue Objectに展開する場合 Array of Arrayの形式でここを渡すconstructor
: ActiveRecord Object => Value Object に展開するときのメソッドconverter
: Setterとして値をセットしたときに使われる convert メソッド
CIDR クラスをValue Objectとして利用する例
dspinhirne/netaddr-rb: A Ruby library for performing calculations on IPv4 and IPv6 subnets.
class NetworkResource < ActiveRecord::Base
composed_of :cidr,
class_name: 'NetAddr::CIDR',
mapping: [ %w(network_address network), %w(cidr_range bits) ],
allow_nil: true,
constructor: Proc.new { |network_address, cidr_range| NetAddr::CIDR.create("#{network_address}/#{cidr_range}") },
converter: Proc.new { |value| NetAddr::CIDR.create(value.is_a?(Array) ? value.join('/') : value) }
end
# This calls the :constructor
network_resource = NetworkResource.new(network_address: '192.168.0.1', cidr_range: 24)
# These assignments will both use the :converter
network_resource.cidr = [ '192.168.2.1', 8 ]
network_resource.cidr = '192.168.0.1/24'
# This assignment won't use the :converter as the value is already an instance of the value class
network_resource.cidr = NetAddr::CIDR.create('192.168.2.1/8')
# Saving and then reloading will use the :constructor on reload
network_resource.save
network_resource.reload