我正在尝试在父母和子女表中添加父母及其子女的数据。这些表中有现有数据,我正在尝试添加其他数据,但我不想重复这些数据。以下是我用来上传数据的代码。子有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
答案 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则完成其余工作。