STUDY MEMO

学習のメモ書き

<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クリエイターズ

Kernel.#load (Ruby 3.0.0 リファレンスマニュアル)

http://interfirm.hatenablog.com/entry/2014/05/30/195044