LoginSignup
0
0

More than 5 years have passed since last update.

Rubyで縦持ちデータから動的にモデルを作る

Last updated at Posted at 2018-03-14

コメントより

縦持ちテーブルをこのように利用することはアンチパターンだそうで、
まだまだ勉強不足であります。
詳しくはこちらで。。。
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に手を加えるだけでカラム追加・削除と同じ効果が得られるようになります。
頻繁にカラム追加が起きるようなテーブルがある場合に、この方法を考慮に入れてみても良いのではないでしょうか。

0
0
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0