从不同的类导入具有不同属性的CSV文件

时间:2016-04-18 17:27:55

标签: ruby-on-rails ruby csv export-to-csv

我需要一个关于如何导入具有不同属性的CSV文件的示例。到目前为止,当我运行我的代码时,我收到一条错误消息,指出未知属性' email'为学生。电子邮件属性可以来自Parent。除了仅为学生导入属性和仅导入父级。如何在学生属性中导入父属性?

我的程序工作在我的学生计划中导出带有父属性的CSV时发现。

任何帮助将不胜感激。

学生模特课:

class Student < ActiveRecord::Base
    belongs_to :parent

  delegate :email,:name,:phone_number,to: :parent, allow_nil: true

         def self.to_csv
            attributes = %w{parent_id email phone_number first_name last_name  age workshop interest registration_date email   }
            CSV.generate(headers: true) do |csv|
              csv << attributes

              all.each do |script|
                csv << attributes.map{ |attr| script.send(attr) }
              end
            end

          end

def self.import(file)
    spreadsheet = open_spreadsheet(file)
    header=spreadsheet.row(1)
    (2..spreadsheet.last_row).each do |i|
      row = Hash[[header,spreadsheet.row(i)].transpose]
    #CSV.foreach(file.path, headers: true) do |row|
      student = find_by_id(row["id"])|| new
      student.attributes = row.to_hash.slice(*row.to_hash.keys)
      student.save!
    end
  end

  def self.open_spreadsheet(file)
    case File.extname(file.original_filename)
    when ".csv" then Roo::CSV.new(file.path)
    when ".xls" then Roo::CSV.new(file.path)
    when ".xlsx" then Roo::CSV.new(file.path)
    else raise "Unknown file type: #{file.original_filename}"
    end
  end

end

学生管理员:

def import
  Student.import(params[:file])
  redirect_to root_url, notice: "student imported."
end
end

查看文件夹:

<h2>Import Students</h2>

<%= form_tag import_students_path, multipart: true do %>
  <%= file_field_tag :file %>
  <%= submit_tag "Import" %>
<% end %>

1 个答案:

答案 0 :(得分:0)

我想建议你的第一件事就是保持你的模型代码很薄。最佳做法是让您的模型仅对数据负责,否则为紫罗兰SRP

class ImportStudentsService
  SUPPORTED_TYPES = ['.csv', '.xls', '.xlsx'].freeze
  STUDENT_ATTRIBUTES = %w(
    parent_id first_name last_name  
    age workshop interest registration_date   
  ).freeze

  PARENT_ATTRIBUTES = %w(email phone_number email).freeze

  def initialize(file)
    @file = file
  end

  def call
    import
  end

  private

  def import
    spreadsheet.each do |row|
      student = Student.find_or_initialize_by(id: row['id'])
      parent = student.parent || student.build_parent
      student.attributes = row.slice(*STUDENT_ATTRIBUTES)
      parent.attributes = row.slice(*PARENT_ATTRIBUTES)
      student.save!
      parent.save!
    end
  end

  def spreadsheet
    unless SUPPORTED_TYPES.include?(File.extname(@file.original_filename))
      raise "Unknown file type: #{@file.original_filename}"
    end
    Roo::CSV.new(@file.path)
  end
end

在控制器中

def import
  ImportStudentsService.new(params[:file]).call
  redirect_to root_url, notice: "student imported."
end

这不是100%正常工作的代码,但这里提出了主要想法。