LoginSignup
34
29

More than 5 years have passed since last update.

Rails 初期データ投入(rake db:seed)について(Rails 4.2, Faker, Gimei, Enumerize, activerecord-import)

Last updated at Posted at 2017-02-25

Railsで初期データを投入する時、rake db:seed を叩くと思う。色んな gem や tips を組み合わせることで幸せになれたので、ここにまとめておく。

なお、ここに書いてある内容は、参考ページに書いてある内容がほとんどであり、色々と集約したものになっている。原文記事の作者様には大変感謝である。

TL;DR

  1. 以下の gem を使うと rake db:seed が捗るようになった
  2. ついでに rake db:seed:user みたいにできるようにしたら db/seeds.rb がスッキリした

前提

Rails歴が浅いので他にベストプラクティスがあるかも。その場合はぜひマサカリコメントして欲しい。

環境

  • ruby 2.3.1
  • Rails 4.2.7.1(db : mysql)
  • faker 1.6.6
  • gimei 0.2.0
  • enumerize 2.0.1
  • activerecord-import 0.17.1

やったこと

まずはgemをインストール

Gemfile
gem 'enumerize'
gem 'activerecord-import'
group :development, :test do
  gem 'faker'
  gem 'gimei'
end

faker の日本語ロケールファイルを取得

stympy/faker : faker/lib/locales

上記ページに ja.yml があるので、ダウンロードして lib/locales/ja.yml に配置。

新規 rake タスクを作成

lib/tasks/seed.rake 作成

vi lib/tasks/seed.rake などで lib/tasks/seed.rake を作成。

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

続いて vi db/seeds.rbdb/seeds.rb を編集。

db/seeds.rb
+ Dir.glob(File.join(Rails.root, 'db', 'seeds', '*.rb')) do |file|
+   load(file)
+ end

コメントで、もっとシンプルな書き方を教えて頂いたので、そちらもあわせてご確認ください。

db/seeds ディレクトリ作成

$ mkdir db/seeds

rake タスクの確認

まずはそのまま rake -T db:seed を打ってみる。

$ rake -T db:seed
rake db:seed  # Load the seed data from db/seeds.rb

次に db/seeds/hoge.rb を作ってからもう一度打ってみる。rake db:seed:hoge が新しくできているのが分かる。

$ touch db/seeds/hoge.rb
$ rake -T db:seed
rake db:seed       # Load the seed data from db/seeds.rb
rake db:seed:hoge  # Load the seed data from db/seeds/hoge.rb

試しに db/seeds/hoge.rb を編集してから rake db:seed:hoge と打ってみる。

$ echo "p 'hoge'" >> db/seeds/hoge.rb
$ cat db/seeds/hoge.rb
p 'hoge'
$ rake db:seed:hoge
"hoge"

同様に db/seeds/fuga.rb を作ってから rake db:seed:fuga および rake db:seed を打ってみる。rake db:seed:fugadb/seeds/fuga.rb だけが、 rake db:seeddb/seeds/*.rb が実行されているのが分かる。

$ echo "p 'fuga'" >> db/seeds/fuga.rb
$ cat db/seeds/fuga.rb
p 'fuga'
$ rake db:seed:fuga
"fuga"

$ rake db:seed
"hoge"
"fuga"

これでモデル毎にファイルを分ければ、不要なデータは投入しなくて良いなど、自由度が上がる。

ダミーデータの投入

実際に作ったファイル

まずは自分が作った db/seeds/user.rb の内容を晒してみる。User モデルにありがちなデータを投入していると思って見て欲しい。

db/seeds/user.rb
# coding: utf-8

# Create dummy users
# Male
users = []
50.times do |no|
  gimei = Gimei.male
  users << User.new(
    user_name: Faker::Internet.user_name,
    email: Faker::Internet.email,
    first_name: gimei.first.kanji,
    first_name_kana: gimei.first.hiragana,
    last_name: gimei.last.kanji,
    last_name_kana: gimei.last.hiragana,
    birthday: Faker::Time.between(40.years.ago, 18.years.ago, :all).to_s[0, 10],
    gender: User.gender.male.value,
    univ_id: University.pluck(:id).sample,
  )
end

# Female
50.times do |no|
  gimei = Gimei.female
  users << User.new(
    user_name: Faker::Internet.user_name,
    email: Faker::Internet.email,
    first_name: gimei.first.kanji,
    first_name_kana: gimei.first.hiragana,
    last_name: gimei.last.kanji,
    last_name_kana: gimei.last.hiragana,
    birthday: Faker::Time.between(40.years.ago, 18.years.ago, :all).to_s[0, 10],
    gender: User.gender.female.value,
    univ_id: University.pluck(:id).sample,
  )
end

# Bulk insert
User.import users

ざっくりと解説

コードそのままだが、流れとしては、

  1. バルクインサートする用の配列変数 users を初期化
  2. 50人分の男性データを users に追加
  3. 50人分の女性データを users に追加
  4. 100人分のユーザーデータを User.import users でバルクインサート

となっている。

activerecord-import の活用

もうお分かりの通り、

  1. 配列の初期化
  2. 配列にデータを追加していく
  3. 最後に Hoge.import hoges

だけで良い。SQLが1回で済む分、毎回 User.create とするより実行速度が早い。

Faker, Gimei の活用

今回は使ってないものもあるが、使えそう(良く使いそう)なものを簡単にまとめておく。

対象データ 利用メソッド サンプル 備考
ユーザー名 Faker::Internet.user_name ollie
メールアドレス Faker::Internet.email nathen@turcotte.org
姓名(漢字) Gimei.kanji 石田 弥安 ※1
姓名(ひらがな) Gimei.hiragana もりた たいさく ※1
姓名(カタカナ) Gimei.katakana ホリエ ケイスケ ※1
名(漢字) Gimei.first.kanji 昇平 ※1
名(ひらがな) Gimei.first.hiragana ひろえ ※1
名(カタカナ) Gimei.first.katakana イクフミ ※1
姓(漢字) Gimei.last.kanji 石田 ※1
姓(ひらがな) Gimei.last.hiragana たにがわ ※1
姓(カタカナ) Gimei.last.katakana タナカ ※1
日付 Faker::Time.between(40.years.ago, 18.years.ago, :all).to_s[0, 10] 1977-08-04 ※2
時刻 Faker::Time.between(40.years.ago, 18.years.ago, :all).to_s[11, 8] 23:44:20 ※2
住所(都道府県) Faker::Address.state 山形県
住所(都道府県:漢字) Gimei.prefecture.kanji 宮崎県 ※1
住所(都道府県:ひらがな) Gimei.prefecture.hiragana ぎふけん ※1
住所(都道府県:カタカナ) Gimei.prefecture.katakana トットリケン ※1
住所(市?) Faker::Address.city 奈々区
住所(市:漢字) Gimei.city.kanji 長岡市 ※1
住所(市:ひらがな) Gimei.city.hiragana いさはやし ※1
住所(市:カタカナ) Gimei.city.katakana ヤマモトグンフジサトマチ ※1
住所(町:漢字) Gimei.town.kanji 黒木町北大淵 ※1
住所(町:ひらがな) Gimei.town.hiragana いいじまみちひがし ※1
住所(町:カタカナ) Gimei.town.katakana カメオチョウ ※1

※1
Gimei.kanji と毎回打つと値が変わるので、Gimei.kanji Gimei.hiragana Gimei.katakana はバラバラになってしまう。同じ名前の情報が欲しい場合は gimei = Gimei.newgimei = Gimei.male gimei = Gimei.female としてから、 gimei.kanji gimei.hiragana gimei.katakana としてやれば良い。

今回自分が作ったものも、あらかじめ gimei = Gimei.male としてからデータを取るようにしている。

※2
DB のフォーマットに合わせて取り出す良い方法が見付からなかったので力技。誰か良い方法を知ってれば教えて欲しい。

※3
Faker は ja.yml を編集していけば、全てのデータが日本語化できると思われる。公式ロケールファイルは情報が少ないので、適宜カスタマイズしていくと良い。(ついでにプルリクしてあげると喜ばれそう)

※4
細かいリファレンスはそれぞれ以下を参照して欲しい。

Enumerize の活用

モデルに Enumerize を使うことを追加。細かい部分は後述の参考ページを見て欲しい。

app/models/user.rb
class User < ActiveRecord::Base
  extend Enumerize
  enumerize :gender, in: {:male => 0, :female => 1}, default: :male, predicates: true, scope: true

i18n 対応。(今回の話とは関係無し)

config/locales/models/users/ja.yml
ja:
  enumerize:
    user:
      gender:
        male: 男性
        female: 女性

Enumerize の定義を追加すると、User.gender.male.value User.gender.female.value などで値を取得できる。直接 0 1 と書くより可読性が上がる。

参考にしたページ

Faker/Gimei

余談だが、以下の記事の通り Faker v1.7.3 でユニーク値の生成(重複の回避)がサポートされたとのこと

Enumerize

activerecord-import

rake db:seed

その他見たけど採用しなかったものたち

好き嫌いとかプロジェクトの方針とかあるので、人によってはこっちの方が良いかもと思い、全部載せておきます。

34
29
2

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
34
29