我想将数据从CSV文件导入到现有的数据库表中。我不想保存CSV文件,只是从它的数据,并把它放入现有的表。我使用Ruby 1.9.2和Rails 3。

这是我的桌子:

create_table "mouldings", :force => true do |t|
  t.string   "suppliers_code"
  t.datetime "created_at"
  t.datetime "updated_at"
  t.string   "name"
  t.integer  "supplier_id"
  t.decimal  "length",         :precision => 3, :scale => 2
  t.decimal  "cost",           :precision => 4, :scale => 2
  t.integer  "width"
  t.integer  "depth"
end

你能给我一些代码,告诉我最好的方法,谢谢。


当前回答

最好使用CSV::Table并使用String。编码(universal_newline:真)。它将CRLF和CR转换为LF

其他回答

yfeldblum回答的简单版本,更简单,也适用于大文件:

require 'csv'    

CSV.foreach(filename, headers: true) do |row|
  Moulding.create!(row.to_hash)
end

不需要with_indifferent_access或symbolize_keys,也不需要先将文件读入字符串。

它不把整个文件一次保存在内存中,而是逐行读取,每行创建一个Moulding。

require 'csv'    

csv_text = File.read('...')
csv = CSV.parse(csv_text, :headers => true)
csv.each do |row|
  Moulding.create!(row.to_hash)
end

更好的方法是将其包含在rake任务中。创建导入。Rake文件在/lib/tasks/中,并将此代码放到该文件中。

desc "Imports a CSV file into an ActiveRecord table"
task :csv_model_import, [:filename, :model] => [:environment] do |task,args|
  lines = File.new(args[:filename], "r:ISO-8859-1").readlines
  header = lines.shift.strip
  keys = header.split(',')
  lines.each do |line|
    values = line.strip.split(',')
    attributes = Hash[keys.zip values]
    Module.const_get(args[:model]).create(attributes)
  end
end

然后在您的终端上运行此命令rake csv_model_import[file.csv,Name_of_the_Model]

下面的模块可以在任何模型上进行扩展,它将根据CSV中定义的列标题导入数据。

注意:

这是一个很棒的内部工具,对于客户使用,我建议添加安全措施和消毒 CSV中的列名必须与DB模式完全相同,否则将无法工作 通过使用表名获取头信息,而不是在文件中定义头信息,可以进一步改进

创建一个名为“csv_importer”的文件。在您的模型/关注点文件夹中

module CsvImporter
  extend ActiveSupport::Concern  
  require 'csv'
  
  def convert_csv_to_book_attributes(csv_path)
    csv_rows = CSV.open(csv_path).each.to_a.compact
    columns = csv_rows[0].map(&:strip).map(&:to_sym)
    csv_rows.shift
    
    return columns, csv_rows
  end
  
  def import_by_csv(csv_path)
    columns, attributes_array = convert_csv_to_book_attributes(csv_path)
    
    message = ""
    begin
      self.import columns, attributes_array, validate: false
      message = "Import Successful."
    rescue => e
      message = e.message
    end
    
    return message
  end
end

将扩展CsvImporter添加到您想要扩展此功能的任何模型中。

在你的控制器中,你可以像下面这样使用这个功能:

def import_file
   model_name = params[:table_name].singularize.camelize.constantize
   csv = params[:file].path
   @message = model_name.import_by_csv(csv)
end

最好使用CSV::Table并使用String。编码(universal_newline:真)。它将CRLF和CR转换为LF