2011年3月3日木曜日

seeds.rbで、CSVを取り込んでみる



環境:rails2.3.8


久しぶりのアップです。


胃の調子が悪かったり、家の問題があったりで。


とりあえず、胃の方はウイルス性の胃炎っぽく、現在回復に向かっております。


で、本題ですが、


初期データを投入するために、seeds.rb に都度データを打ち込んでいたのですが、


今回、大量データを入れる必要が発生しました。


でも、これをseeds.rbにだらだら書くのはちょっと・・・


とネットで探してたら見つけました!


import seed data from .csv or .yml for Rails 2.3.4+ — Gist


なんと、用意したCSVをseeds.rbで取り込んじゃうクラスです。


使い方


まずは、FasterCsvがインストールされている必要があります。


sudo gem install fastercsv


して下さい。


で、seeds.rbは以下をコピペ



############################################
# CSV YML 取込みクラス
############################################
require 'fastercsv'

class SeedImporter
def initialize
@model = nil
@with_id = false
end

def run
Dir.glob( File.dirname(__FILE__) + '/seeds/**/*.{yml,csv}' ).each { |seed|
send( "read_#{File.extname( seed )[1..seed.bytesize]}_seed", seed )
}
end

def read_csv_seed( file )
init_model( file, '.csv' )
FasterCSV.table( file,
{ :headers => true,
@with_id = csv.headers.include?( 'id' )
}
FasterCSV.open( file,
{ :headers => true,
if ( @with_id )
csv.each { |row| create_and_save_with_id( row.to_hash ) }
else
csv.each { |row| create_and_save( row.to_hash ) }
end
}
end

def read_yml_seed( file )
init_model( file, '.yml' )
YAML.load_file( file ).each_pair { |k, v|
if ( v.has_key?( 'id' ) )
create_and_save_with_id( v )
else
create_and_save( v )
end
}
end

def to_model( file, suffix )
File.basename( file, suffix ).classify
end

def init_model( file, suffix )
@model = Object.const_get( to_model( file, suffix ) )
end

def create_and_save( data )
@model.create( data )
end

def create_and_save_with_id( data )
record = @model.new( data )
record['id'] = data['id']
record.save!
end
end

############################################
# CSV取込み処理
############################################
SeedImporter.new.run



後はdbフォルダに、seedsフォルダを作り、その中にCSVを入れておきます。


CSVは例えばこんな感じ。


ファイル名:{テーブルID}.csv



id,jis_code,state_name,city_name
1,01101,北海道,札幌市中央区
2,01102,北海道,札幌市北区
3,01103,北海道,札幌市東区 


以上で準備完了!


rake db:seed を実行すれば、上記csvが取り込まれます。


ちなみに、今回は84kbくらいのcsvを取り込みましたが結構時間がかかりました。


また、このクラスにはdeleteは無いので、状況に応じてdelete_allを入れる必要があります。





0 件のコメント:

コメントを投稿