はじめに
シードデータの読み込み順序を制御する方法として、番号によるプレフィックスをファイル名につけて管理する方法が一般的だと思います。しかしこの場合、すでに多くの人が経験されているように、頻繁に(その上なんの生産性もない)番号の差し替えが生じることになりますよね。
そうなる前にあまり手間をかけずに管理する方法を提案したいと思います。
今回はseed-fuを用いていますが、基本的な考え方は標準のseedシステムでも同じです。
結論
file_names = [
'categories.rb',
'publishers.rb',
'authors.rb',
'books.rb'
]
dir = Rails.root.join('db', 'fixtures', 'development', 'seeds')
file_names.each do |file_name|
puts "== Seed from #{dir}/#{file_name}"
require "#{dir}/#{file_name}"
end
シードデータを読み込む際にディレクトリ直下のシードファイルすべてを呼ぶのではなく、読み込みたいファイルをロジックで制御するようにしたファイルを読み込むように変更する。
方法
全体の流れとしては
- gemの導入
- コマンドの上書き(これは行わなくても良い)
- ディレクトリ構成の変更
- ツラミがなくなるシードファイルの作成
となる
seed-fuを入れる
gem 'seed-fu', '~> 2.3', '>= 2.3.9'
bundle install
rails db:seedを上書きする
デフォルトのdb:seed
は利用しないので上書きする。
rails g task seed
# 好みによってディレクトリを移動する
namespace :db do
desc 'db:seedコマンドをdb:seed_fuにする'
task :seed do
Rake::Task['db:seed_fu'].invoke # 当記事の参考を参照
end
end
シードファイルを入れるディレクトリを作成する
seed-fuではfixturesディレクトリ直下に環境名のディレクトリがある場合、fixtures直下に加え、環境名直下のファイルも全て読み込む仕様になっている。そのため、環境名直下にロジックを置く。
おそらく一般的であろうプレフィックスのついたディレクトリ構成
app/
└ db/
└ fixtures/
├ development/
│ └ 01_categories.rb
│ └ 02_publishers.rb
│ └ 03_authors.rb
│ └ 04_books.rb
つらみがなくなるディレクトリ構成
app/
└ db/
└ fixtures/
├ development/
│ ├ seeds/
│ │ └ authors.rb
│ │ └ books.rb
│ │ └ categories.rb
│ │ └ publishers.rb
│ │
│ └ seed.rb => ここにロジックを入れる
└ production/
ディレクトリ構成はdevelopmentと同じ
このようなディレクトリ構成にしておくと、development環境でrails db:seed
を実行したときにdb/fixtures/development/seed.rb
のみが呼ばれる。
seed.rbで読み込み順序を制御
file_names = [
'categories.rb',
'publishers.rb',
'authors.rb',
'books.rb'
]
dir = Rails.root.join('db', 'fixtures', 'development', 'seeds')
file_names.each do |file_name|
puts "== Seed from #{dir}/#{file_name}"
require "#{dir}/#{file_name}"
end
以上で完了。
読み込み順序を変更したいとき
例えばsub_categories
を追加してpublishers
の前に読み込ませたいとき、今までは
01_categories.rb -> 01_categories.rb
new 02_sub_categories.rb
02_publishers.rb -> 03_publishers.rb
03_authors.rb -> 04_authors.rb
04_books.rb -> 05_books.rb
と番号を変えていたが
file_names = [
'categories.rb',
'sub_categories.rb',
'publishers.rb',
'authors.rb',
'books.rb'
]
と配列の中身を変更すればよいだけになる。
共通のシードデータが必要になった場合
ここから先は記憶を頼りに記述しており、動作確認はしていないことに注意してほしい。
上記構成では、番号の差し替えは発生しなくなったものの、複数の環境で共通の情報をもったシードファイルを流し込みたい場合には、それぞれの環境ディレクトリで同じファイルを作成することになる。
当然のことであるが怠惰代表の威信にかけて、そのようなことは決して行ってはならず、共通のファイルを読み込む設定を導入するべきである。その場合は
改善後のディレクトリ構成
app/
└ db/
└ fixtures/
├ commons/ => 新規で作成
├ development/
│ ├ seeds/
│ │ └ authors.rb
│ │ └ books.rb
│ │ └ categories.rb
│ │ └ publishers.rb
│ │
│ └ seed.rb
└ production/
として共通のシードファイルを配置するディレクトリを作成。
利用方法の例として、今回はcategories.rb
をdevelopment、productionの両方で呼び出すこととする。
app/db/fixtures/commons/categories.rb
を作成し中身に下記のようなクラスメソッドを定義する。
class Categories
def self.seed
Category.seed(:name,
{id: 1, name: 'テクノロジー'},
{id: 2, name: 'ポエム'}
)
end
end
次に、development/seeds/categories.rb
、produciton/seeds/categories.rb
それぞれで先ほど作成した共通ファイルを読み込む
require_relative '../../commons/categories'
Categories.seed
このように変更することにより、環境以下のcategories.rb
が読み込まれた際にseedが実行され共通のシードデータが反映される。
最終的な構成
app/
└ db/
└ fixtures/
├ commons/
│ └ categories.rb
├ development/
│ ├ seeds/
│ │ └ authors.rb
│ │ └ books.rb
│ │ └ categories.rb
│ │ └ publishers.rb
│ │
│ └ seed.rb
└ production/ developmentと同じ構成
参考