読者です 読者をやめる 読者になる 読者になる

くりにっき

ドリコムのプリキュアの人です

heart_seedというマスタデータDB投入用のgemを作りました

Ruby Rails Padrino gem

マスタデータ作成時の問題点

  • xlsやxlsxはExcelで編集するのには向いてるけど、バイナリなのでgitやsvnとの相性は悪い
    • diffが見れない
  • yamlはdiffが見やすいけど大量のマスタデータの編集には向かない
    • 行列構造はExcelで編集するのが楽
    • 非エンジニアにyamlを直接編集してもらうのはつらい(エンジニアでもつらい)

ということで、xlsをyamlに変換して、さらにyamlをseedとしてDBに投入するためのgemを作りました。(マスタデータの編集時はxlsとyamlを同時にcommitする想定)

元々padrinoで使う予定だったのでpadrinoを想定してますが一応railsも対応してます。

使い方

  1. bundle exec rake heart_seed:init で設定ファイルやディレクトリが作られる
  2. xlsを作る
  3. bundle exec rake heart_seed:xlsでxlsをyamlに変換
  4. bundle exec rake db:seed or bundle exec rake heart_seed:db:seedyamlからDBに投入
  5. TABLESCATALOGS がオプションで使えます(後述)

Railsじゃなかったら下記を Rakefile に追加してください

require 'heart_seed/tasks'

仕様

githubにも英語で書いていますが重要な事なので日本語でも失礼します

xls/xlsx のフォーマット

例えばこんなシートがあった時は

id title description created_at this is dummy
1 title1 description1 2014/6/1 12:10 foo
2 title2 description2 2014/6/2 12:10 baz
  • シート名 = テーブル名に対応
    • DBに存在しないテーブルは無視される
  • 1行目がヘッダ行でカラム名をいれる
    • 途中に空のセルがあった時はそこより右側は全部無視される
  • 2行目以降が実際のレコード
    • タイムスタンプは ActiveSupport::TimeWithZone が使われます。
    • roo 単体だとExcelのタイムスタンプはUTCとして解釈されるのでheart_seedの中でごにょごにょしてます

yamlのフォーマット

上記の例だとこんな感じのyamlが作られます(ActiveRecord::FixtureSet と同じフォーマット)

---
articles_1:
  id: 1
  title: title1
  description: description1
  created_at: '2014-06-01 12:10:00 +0900'
articles_2:
  id: 2
  title: title2
  description: description2
  created_at: '2014-06-02 12:10:00 +0900'

catalog

catalogとは似たようなテーブルのグループみたいなものです。

config/heart_seed.ymlにこんな感じで書きます。

catalogs:
  user:
  - users
  - user_profiles

下記のように実行することでusesとuser_profilesの2つのテーブルに対して db:seed できます

CATALOGS=user bundle exec rake db:seed

production(本番)への db:seedは TABLEかCATALOGどっちか必須

db:seed にオプション無ければ全テーブルにseedを適用しますが、productionでこれをやると意図せずデータを書き換えたり巻き戻ったりするかもしれないので出来ないようにしています。

シャーディング(垂直分割)対応

大規模なアプリだと 1つのデータベースを複数のシャードに分割してるかもしれませんが、そういう時に db/seeds.rb に

SHARD_NAMES = %W(
  #{Rails.env}
  shard_#{Rails.env}
  shard2_#{Rails.env}
)
HeartSeed::DbSeed.import_all_with_shards(shard_names: SHARD_NAMES)

こういう風に書くことで、全てのシャードにseedを投入することができます。(マスタデータは使用頻度高いので全てのシャードからJOINできるようにする想定)

頑張ったこと

名前の由来

seed = 種 = 「こころの種(heart seed)が生まれそうですぅ〜」

f:id:sue445:20140710002806p:plain