CSV在Rails中上传

时间:2018-09-19 17:35:45

标签: ruby-on-rails csv ruby-on-rails-5 import-csv

我正在尝试在父母和子女表中添加父母及其子女的数据。这些表中有现有数据,我正在尝试添加其他数据,但我不想重复这些数据。以下是我用来上传数据的代码。子有parent_id。

parent.rb

has_many :children, dependent: :destroy    

def self.import(file)
    CSV.foreach(file.path, headers:true) do |row|
        parent = Parent.find_or_update_or_create_by(
            parent_1_firstname: row['parent_1_firstname'],
            parent_1_lastname: row['parent_1_lastname'],
            address: row['address'],
            address_line_2: row['address_line_2'],
            city: row['city'],
            province: row['province'],
            postal_code: row['postal_code'],
            telephone_number: row['telephone_number'],
            email: row['email'], 
            family_situation: row['admin_notes'],
            gross_income: row['gross_income'],
            created_by_admin: row['created_by_admin'],
            status: row['status']


            )

        parent.children.find_or_create_by(
              firstname: row['firstname'],
              lastname: row['lastname'],
              dateofbirth: row['dateofbirth'],
              gender: row['gender']

            )
    end
end

child.rb

belongs_to :parent

我面临的错误是当我选择下面要上传的csv文件时,这是我得到的错误。

undefined method `find_or_update_or_create_by' for #<Class:0x00007f8797be74b0> Did you mean? find_or_create_by

我在下面添加了一个示例csv。请帮助我找出问题所在。

parent_1_firstname,parent_1_lastname,address,address_line_2,city,province,postal_code,telephone_number,email,admin_notes,gross_income, created_by_admin ,status,firstname,lastname,dateofbirth,gender
Nav,Deo,College Road,,Alliston,BC,N4c 6u9,500 000 0000,nav@prw.com,"HAPPY",13917, TRUE , Approved ,Sami,Kidane,2009-10-10,Male

2 个答案:

答案 0 :(得分:1)

  

未定义的方法“ find_or_update_or_create_by”用于   类别:0x00007f8797be74b0您的意思是? find_or_create_by

AFAIK,Rails中没有find_or_update_or_create_by方法。除非您在Parent模型中将其定义为类方法,否则无法在类上调用该方法。我相信您打算使用find_or_create_by。更改

Parent.find_or_update_or_create_by

Parent.find_or_create_by

更新

  

除非保存了父级,否则您不能调用create

好,因此parent未保存,这可能是由于任何验证失败所致。将Parent.find_or_create_by更改为Parent.find_or_create_by!(如 @jvillian 所述),这将引发验证错误消息的异常。解决错误,您就可以了。

答案 1 :(得分:0)

为了不必通过find_or_create_by逻辑对各种嵌套循环进行硬编码,有一个名为 DutyFree 的gem使这样的导入和导出变得非常轻松。它可以智能地分析模型上的has_many和belongs_to关联,并基于这些关系确定如何正确地跨多个目标表保存每个导入的行。根据数据是否存在执行创建或更新。

为了从上面演示您的示例,我根据您提供的CSV数据编写了RSpec测试: https://github.com/lorint/duty_free/blob/master/spec/models/parent_complex_spec.rb

还有一个更简单的示例,其中只有6列: https://github.com/lorint/duty_free/blob/master/spec/models/parent_simple_spec.rb

关于这个gem的一件好事是,在配置了列定义以进行导入之后,由于所有工作都来自同一模板,因此您可以免费获得导出。对于此示例,这里是模板,该模板允许CSV中的列名与数据库列完美对齐:

IMPORT_TEMPLATE = {
  uniques: [:firstname, :children_firstname],
  required: [],
  all: [:firstname, :lastname, :address, :address_line_2, :city, :province, :postal_code,
        :telephone_number, :email, :admin_notes, :gross_income, :created_by_admin, :status,
    { children: [:firstname, :lastname, :dateofbirth, :gender] }],
  as: {
        'parent_1_firstname' => 'Firstname',
        'parent_1_lastname' => 'Lastname',
        'address' => 'Address',
        'address_line_2' => 'Address Line 2',
        'city' => 'City',
        'province' => 'Province',
        'postal_code' => 'Postal Code',
        'telephone_number' => 'Telephone Number',
        'email' => 'Email',
        'admin_notes' => 'Admin Notes',
        'gross_income' => 'Gross Income',
        'created_by_admin' => 'Created By Admin',
        'status' => 'Status',

        'firstname' => 'Children Firstname',
        'lastname' => 'Children Lastname',
        'dateofbirth' => 'Children Dateofbirth',
        'gender' => 'Children Gender'
      }
}.freeze

在parent.rb中使用此代码,您可以调用Parent.df_import(your_csv_object)或Parent.df_export,而gem则完成其余工作。