<Ruby on Rails> seedの分割
分割理由
DBの初期データ投入のためにseedファイルを使用したが、量が多いので分割して見やすくしたかった。
1の方法がスマートだが、2の方法も一応記入しておく。
共通
dbにseedsディレクトリを作成
$ mkdir db/seeds
seedsディレクトリの下に任意のseedファイルを作成
$ touch db/seeds/result.rb
方法1. seed.rbにseedsディレクトリ
seeds.rbにseedsディレクトリ以下を読み込むように設定
Dir.glob(File.join(Rails.root, 'db', 'seeds', '*.rb')) do |file| load(file) end
これにより、bundle exec rails db:seedでseedsディレクトリ以下のrbファイルが読み込まれ、初期データを一度に作成することができる。
方法2. rakeタスクとして保存
rakeタスクに実行方法を記載
lib/tasks/seed.rakeを作成
$ mkdir lib/tasks/seed.rake
Dir.glob(File.join(Rails.root, 'db', 'seeds', '*.rb')).each do |file| desc "Load the seed data from db/seeds/#{File.basename(file)}." task "db:seed:#{File.basename(file).gsub(/\..+$/, '')}" => :environment do load(file) end end
●File.joinFile.join("a","b")と書いた時、"a/b"となる。そのため、File.join(Rails.root, 'db', 'seeds', '*.rb')の部分は
pry(main)> Rails.root => #<Pathname:/Users/user_name/workspace/runteq/PF/kinoko2>
ということから、Users/user_name/workspace/runteq/PF/kinoko2/db/seeds/*rbを指定したこととなる。
●Dir.grobは、ワイルドカードの展開を行い、パターンにマッチするファイル名を文字列の配列として返すので、
pry(main)> Dir.glob(File.join(Rails.root, 'db', 'seeds', '*.rb')) => ["/Users/user_name/workspace/runteq/PF/kinoko2/db/seeds/result.rb"]
となる。
seedsディレクトリ内に、別のファイルwise_saying.rbがあるとすると、
pry(main)> Dir.glob(File.join(Rails.root, 'db', 'seeds', '*.rb')) => ["/Users/user_name/workspace/runteq/PF/kinoko2/db/seeds/result.rb", "/Users/user_name/workspace/runteq/PF/kinoko2/db/seeds/wise_saying.rb"]
となる。
●descメソッドは、直後のRakeタスクの説明を登録するため、 "Load the seed data from db/seeds/#{File.basename(file)}."がtaskの説明文として登録される。
$ bundle exec rake -D ... rake db:seed:result Load the seed data from db/seeds/result.rb. rake db:seed:wise_saying Load the seed data from db/seeds/wise_saying.rb. ...
●File.basename(filename)は、filename の一番後ろのスラッシュに続く要素を返す。
[12] pry(main)> Dir.glob(File.join(Rails.root, 'db', 'seeds', '*.rb')).each {|file| p "#{File.basename(file)}."} "result.rb." "wise_saying.rb."
●正規表現を使ってdb/seeds下のファイル名の拡張子名を除外する。 メタ文字をリテラルのように、文字としてマッチさせるためには、\をつける。(メタ文字:( ) [ ] { } . ? + * | )
..:いずれかの1文字+:1回以上 (greedy)
$:行末にマッチする。行末とは文字列の末尾もしくは改行の手前を意味する。
/..+$/という正規表現は、デリミタの/(スラッシュ)で囲まれていて、/※の後にいずれかの文字が1つ以上ある、文字列を指している。※ /(スラッシュ)は(バックスラッシュ)でエスケープされている。
gsub(pattern, replace)は、文字列中でpatternにマッチする部分全てを文字列replaceで置き換えた文字列を生成して返すので、
pry(main)> Dir.glob(File.join(Rails.root, 'db', 'seeds', '*.rb')).each {|file| p "#{File.basename(file).gsub(/\..+$/, '')}"} "result" "wise_saying"
となり、"db:seed:#{File.basename(file).gsub(/..+$/, '')}"はdb:seed:resultとdb:seed:wise_sayingになり、taskが定義される。
●taskが実行されるとファイルが読み込まれるようにするために、load(file)でRubyのプログラムfileをロードして実行する。ロードするモジュールとしてはrequireもあるが、require はライブラリのロードに使用され、loadは設定ファイルの読み込みなどに使用される。
rakeタスクに反映されてるか確認
$ rake -h ... → -T, --tasks [PATTERN] Display the tasks (matching optional PATTERN) with descriptions, then exit. -AT combination displays all of tasks contained no description. ... (オプションのPATTERNに一致する)タスクを説明とともに表示し、終了する。 -ATコンビネーションでは、説明のないタスクをすべて表示します。
$ bundle exec rake -T ... rake db:seed:result # Load the seed data from db/seeds/result.rb rake db:seed:wise_saying # Load the seed data from db/seeds/wise_saying.rb ...
参考文献
Railsでseedデータを分割して実行できるようにする - Passion make things more better
File.join (Ruby 3.0.0 リファレンスマニュアル)
Dir.[] (Ruby 3.0.0 リファレンスマニュアル)
File.basename (Ruby 3.0.0 リファレンスマニュアル)
Kernel#desc (Ruby 3.0.0 リファレンスマニュアル)
正規表現とは?メタ文字とサンプル一覧 | WWWクリエイターズ