コメントより
縦持ちテーブルをこのように利用することはアンチパターンだそうで、
まだまだ勉強不足であります。
詳しくはこちらで。。。
http://kyabatalian.hatenablog.com/entry/2016/12/19/193430
はじめに
システム開発を行なっていると、頻繁にカラムの追加が発生するようなテーブルに出くわすことがあります。
その都度テーブル定義を変更すると言うのも一つの解法ですが、データを縦持ちにして変更に強くするというのも一つの手です。
けれど、プログラム上では一つのインスタンスとして扱いたい場合には、縦持ちテーブルは扱いづらいのです。
そこで、縦持ちテーブルから一つのモデルインスタンスを作成する方法をご紹介します。
データ
今回は適当なデータとして以下を用意しました。
details = [
{'id' => 1, 'key' => 'name', 'value' => 'hoge'},
{'id' => 2, 'key' => 'height', 'value' => '10' },
{'id' => 3, 'key' => 'width', 'value' => '5' },
]
モデルクラス
通常であれば、上記のようなデータに対して、
class Profile
attr_accessor :name
attr_accessor :height
attr_accessor :width
end
prof = Profile.new
prof.name = (details.find {|d| d['key'] == 'name'})['value']
prof.height = (details.find {|d| d['key'] == 'height'})['value']
prof.width = (details.find {|d| d['key'] == 'width'})['value']
という形で各keyに対してプロパティを作成していきます。
これでも良いのですが、今回は動的にインスタンスを作成してみます。
class Detail
PROP = {
'name' => Proc.new {|val| val},
'height' => Proc.new {|val| val.to_i},
'width' => Proc.new {|val| val.to_i},
}
end
class Profile
Detail::PROP.each do |key, val|
attr_accessor key.to_sym
end
def initialize(details)
Detail::PROP.each do |key, val|
detail = details.find {|d| d['key'] == key}
if detail
send(key + '=', val.call(detail['value']))
end
end
end
end
prof = Profile.new details
DetailクラスでプロパティのKeyとValueの変換方法を定義しています。
ProfileクラスはDetailクラスの内容を元にプロパティの動的生成と、動的な初期化を行なっています。
考察
ここまでやる必要あるかどうかはそれぞれのプロジェクトに寄るでしょうが、Detail::PROPに手を加えるだけでカラム追加・削除と同じ効果が得られるようになります。
頻繁にカラム追加が起きるようなテーブルがある場合に、この方法を考慮に入れてみても良いのではないでしょうか。