実行中のモデルからマイグレーションの利用
テーブルの追加、削除については、ActiveRecord::Migrationを利用して処理することにした。データベースへの接続やSQLを意識せず、Rubyのコードとして書けるので、こっちの方が楽。変更後のコードは、以下のようになった。
- モデル
- app/models/csv.rb
class Csv < ActiveRecord::Base validates_uniqueness_of :file_name def validate errors.add(:file_name, "アップロードするファイルを指定してください。") if @file.nil? || @file.size == 0 end # Tempfileオブジェクトをインスタンス変数に保存する。 # new()や、update_attributes()の時、呼び出される。 def tempfile=(file) return if file.nil? || file.size == 0 @file = file self.file_name = file.original_filename self.file_size = file.size end # テーブルを追加する。 def create_csv_table ActiveRecord::Migration.create_table table_name do |t| csv_columns.each do |f| t.column f, :string end end end def table_name File.basename(self.file_name, ".*") end def csv_columns # 「"」を取り除いて、文字コードをUTF-8に変換して、改行で区切った配列を返す。 str = @file.read.gsub(/"+/, '') str = NKF.nkf('-w', str) lines = str.split("\n") # 配列の先頭を取り出して、カンマで区切った配列にして、余分な空白を削除する。 columns = lines.shift.split(",").collect{|n| n.strip} # id列が存在しなければ追加する。 if columns.index("id").nil? id = 0 lines.collect! {|line| id +=1; "#{id},#{line}"} end # インポート用のファイルを保存する。 File.delete("public/temp.csv") rescue nil File.open("public/temp.csv", "wb") do |f| f.write(lines.join("\n")) end # 最初のidフィールドは、読み飛ばす。 columns.shift if columns.first == 'id' columns end # csvデータをインポートする。 # インポートを高速化するため、sqlite3のインポート命令を、直接コマンド実行する。 def import_csv env = ENV['RAILS_ENV'] || 'development' system("sqlite3", "-separator", ",", "db/#{env}.sqlite3", ".import public/temp.csv #{table_name}") end # テーブルを削除する。 def drop_csv_table ActiveRecord::Migration.drop_table(table_name) end end