4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Rails|シードデータの読み込み順序を番号で制御するつらみから抜け出そう

Last updated at Posted at 2020-11-30

環境
Static Badge
Static Badge

はじめに

シードデータの読み込み順序を制御する方法として、番号によるプレフィックスをファイル名につけて管理する方法が一般的だと思います。しかしこの場合、すでに多くの人が経験されているように、頻繁に(その上なんの生産性もない)番号の差し替えが生じることになりますよね。
そうなる前にあまり手間をかけずに管理する方法を提案したいと思います。

今回はseed-fuを用いていますが、基本的な考え方は標準のseedシステムでも同じです。

結論

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

シードデータを読み込む際にディレクトリ直下のシードファイルすべてを呼ぶのではなく、読み込みたいファイルをロジックで制御するようにしたファイルを読み込むように変更する。

方法

全体の流れとしては

  1. gemの導入
  2. コマンドの上書き(これは行わなくても良い)
  3. ディレクトリ構成の変更
  4. ツラミがなくなるシードファイルの作成

となる

seed-fuを入れる

Gemfile
gem 'seed-fu', '~> 2.3', '>= 2.3.9'
$
bundle install

rails db:seedを上書きする

デフォルトのdb:seedは利用しないので上書きする。

$
rails g task seed
lib/tasks/db/seed.rake
# 好みによってディレクトリを移動する
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で読み込み順序を制御

db/fixtures/development/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

と番号を変えていたが

seed.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を作成し中身に下記のようなクラスメソッドを定義する。

.rb
class Categories
  def self.seed
    Category.seed(:name, 
                  {id: 1, name: 'テクノロジー'},
                  {id: 2, name: 'ポエム'}
                  )
  end
end

次に、development/seeds/categories.rbproduciton/seeds/categories.rbそれぞれで先ほど作成した共通ファイルを読み込む

.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と同じ構成

参考

4
0
0

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
4
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?