Railsアプリのマスターデータ管理 Seed Fu ベタープラクティス
Railsアプリ開発におけるマスターデータの扱い方は大きく次の3つです。
- 標準機能のseedを利用する
- migrationを利用する
- その他
選択肢で言うとその他になりますが、私は複数の現場で導入してきたのSeed FuというGemをおすすめしています。この記事ではSeed Fuを利用する際のベタープラクティスを紹介します。
おすすめの記法
シンタックスシュガーとして用意されている下記の記法を用いましょう。マスターデータは基本的に静的な値を取り扱うもので、テーブルにレコードとして挿入されることがわかりやすいこの記法がおすすめです。Seed Fuを全く知らない人もすぐ理解してくれます。*1
都道府県のマスターデータを定義する例
Prefecture.seed(:id, { id: 1, name: "北海道" }, { id: 2, name: "青森県" }, { id: 3, name: "岩手県" }, # ~中略~ { id: 47, name: "沖縄県" } )
開発環境用に大量のデータをループで挿入したいときなど、向かないと判断した時は他の記法を利用しましょう。ここでは説明しません。素直にREADMEを読みましょう。 github.com どうしても日本語情報がいい人は以下の記事を参照ください。 qiita.com
変更頻度に合わせた書き方
ほぼ確実に変更がありえず、誤って変更されることを防ぎたい場合はseed_once
で書きましょう。
Prefecture.seed_once(:id, { id: 1, name: "北海道" }, { id: 2, name: "青森県" }, { id: 3, name: "岩手県" }, # ~中略~ { id: 47, name: "沖縄県" } )
こうするとid 1~47で存在しないものにのみinsertが行われるようになります。 (seedの場合は内容が異なるレコードは更新してくれます)
そもそもDBに保存するということは永続化したいけど変更もしたいマスターデータではないのか?という話もあります。プログラム内に定数で持つことも可能ですが、RDBに入れておくとBIツールでデータのみを参照する際にもわかりやすいといった利点もあります。 結局はケースバイケースです。その場に応じた判断をしましょう。
依存関係にあるマスターデータ挿入順序対策
マスターデータで外部キーを持つような依存関係になるものもあるでしょう。例えば都道府県と地方のような関係です。 Seed Fuはファイル名のアルファベット順で実行します*2*3。それを利用して、ファイルのプリフィックスに数字をつけましょう。一番最初に実行する必要があるファイルのプリフィックスは0です。私は同時実行で問題ないファイルも同じ数字を設定します。
地方のマスターデータを定義ファイル(00_areas.rb)
Area.seed_once(:id, { id: 1, name: "北海道地方" }, { id: 2, name: "東北地方" }, # ~中略~ { id: 8, name: "九州地方" } )
都道府県のマスターデータ定義ファイル(01_prefectures.rb)
Prefecture.seed_once(:id, { id: 1, name: "北海道", area_id: 1 }, { id: 2, name: "青森県", area_id: 2 }, { id: 3, name: "岩手県", area_id: 2 }, # ~中略~ { id: 47, name: "沖縄県", area_id: 8 } )
※二桁数字を採用しているのは開発用テストデータと合わせてファイル数が多くなることがあるためです。*4
同一ファイル内に書くことでより直感的に順序を制御する方法もあります。とはいえ、データが増えた時に見通しが悪くなったり、検索性が下がったりするため、私は1modelに対して1seedファイルを作成しています。
Seed Fu Gemを意識せずに実行させる
通常のrails db:seed
コマンド実行時にSeed Fuが呼び出されるように設定しましょう。
db/seeds/seeds.rb
SeedFu.seed
標準的な方法ではrails db:seed_fu
という簡単ですが独自コマンドが必要です。しかし、前述のように標準のseed実行時に呼び出す設定をすることで開発メンバー全員がGem特有のコマンドを覚えずにすみます。
また、この設定をすると標準のseedで管理していたものをSeed Fuに切り替えるときにも、CIやDeployの設定変更が不要になります。 (もともとseedを実行する設定になっているはずのため)
自動テスト実行前に一度だけマスターデータを挿入する
自動テストは副作用をなくす意味でもDBがクリーンな状態で実行されます。*5しかし、マスターデータについては存在することを前提に自動テストを実行したいはずです。 RSpecによる自動テストの場合、実行前に一度だけSeedFu.seedを実行するように次の記述をします。
spec/spec_helper.rb (rails_helper.rbの場合もある)
RSpec.configure do |config| config.before(:suite) do SeedFu.seed end end
自動テストにおいて副作用をより厳密になくすため、Database Cleanerを合わせて利用する場合はこちらの記事がとても参考になります。 blog.inouetakuya.info