seedについてまとめてみる
seeds関連ファイルの階層化
初期の状態だとdb/seeds.rb
だけを読み込んで実行するいという流れだが、テーブル数や登録するレコード数が多かったりすることで行数が長くなり、管理がしにくくなってしまう。
そのため、下記のようにRailsの環境で階層化し、その中に各テーブルごとにファイルを配置するような構成にした。
例:
usersテーブル
postsテーブル
commentsテーブル
- db
- seeds.rb
- seeds
- production
- test
- development
- users.rb
- posts.rb
- comments.rb
db/seeds.rb
table_names = %w(users posts comments) table_names.each do |table_name| path = Rails.root.join("db/seeds",Rails.env,table_name + ".rb") if File.exist?(path) puts "Creating records for #{table_name}" require path end end
流れとしては、seeds.rb
でseedsディレクトリ配下にある各テーブルのrubyファイルを読み込んで、その中に書かれているsqlを実行していく。
最初に配列であるtable_names
にテーブル名を格納してeach文
でテーブル名と一致するrubyファイルのパスを取得し、require
で読み込む。
各テーブルのrubyファイルにはcreate
でレコード挿入のコードを記述する。
db/seeds/development/posts.rb
Posts.create( title: "test", entry: "this is a test entry.", publish_date:Date.today )
BULK INSERTを使って高速化
テストする際はレコードを大量に挿入したいという状況が多いかと思う。
for文
やらwhile文
で一回一回insert
を実行してもいいのだが、MYSQLには大量データを一回のinsert
で挿入することができるBULK INSERTという機能がある。
そこで、このBULK INSERTをactiverecordで実行できるようにするactiverecord-import
というGemを使う。
insert
よりもかなりパフォーマンス向上に繋がるということ。
参考URL
ActiveRecordで複数レコード、BULK INSERTする方法とパフォーマンスについて
Gemfile
gem 'activerecord-import'
使い方は下記のようにモデルのインスタンスを一旦配列に格納しておき、import
メソッドでBULK INSERTを実行するという流れである。
arr = [] 1.upto(100) do |i| arr << Post.new( title:"test#{i}", entry: "this is a test#{i} entry.", publish_date:Date.today + eval("#{i}.days") ) end Post.import arr
レコードとオートインクリメントの初期化
毎回手動でレコードやオートインクリメントを初期化するのは面倒だ。
レコードをinsert
する前に下記の記述で初期化しようとしたが、オートインクリメントの初期化が何故かうまくいかない。。
Post.delete_all Post.connection.execute("ALTER TABLE posts AUTO_INCREMENT = 0;")
そこでTRUNCATE
コマンドを使ってみる。
上記はレコードを全て削除してオートインクリメントを初期化する方法だが、TRUNCATE
は一旦テーブルを削除して,再度作りなおすコマンド。
こちらのほうがスッキリしてるし、ちゃんと動作もするのでこちらを採用した。
Post.connection.execute("TRUNCATE TABLE posts;")
最後に
seed
コマンドを実行する。
bundle exec rake db:seed
Creating records for users Creating records for posts Creating records for comments
deviseを使う場合
- 単純に
password
に文字列を指定するだけで、暗号化してくれる。 - Deviseの登録時の仕様上、BULK INSERTは使えないので素直に
create
。
db/seeds/development/users.rb
1.upto(100) do |i| User.create( username: "yamada#{i}", email: "yamada#{i}@example.com", password: "password", ) end