我的rails应用程序中具有导入CSV功能。我有父母桌和孩子桌。父母与孩子有很多联系。我可以从CSV获取父级详细信息,但无法提取子级详细信息。请帮忙。我该如何实现?
parents_controller.rb
def import
@parent = Parent.import(params[:file])
redirect_to main_admin_path, flash: { success: "Parents Imported" }
end
parent.rb
has_many :children, dependent: :destroy
def self.import(file)
CSV.foreach(file.path, headers:true) do |row|
Parent.create! row.to_hash
end
end
routes.rb
resources :parents do
collection { post :import }
resources :children
end
main_admin.html.erb
Import Parents
<%= form_tag import_parents_path, multipart:true do %>
<%= file_field_tag :file %>
<%= submit_tag "Import"%>
<% end %>
parent.csv
parent_1_firstname,parent_1_lastname,address,childfirstname,childlastname,childdateofbirth
John,Wilson,68 Bell Road,Jessica,Wilson,2002-11-11
John,Wilson,68 Bell Road,Josh,Wilson,2006-10-01
答案 0 :(得分:0)
您应该使用find_or_create_by
方法来创建您的父母。
仅在那之后,您应该创建子代。它是这样的:
# parent.rb
def self.import(file)
CSV.foreach(file.path, headers:true) do |row|
parent = Parent.find_or_create_by(
name: row["parent_1_firstname"] + row["parent_1_lastname"],
address: row["address"],
# ...
)
parent.children.find_or_create_by(
name: row["childfirstname"] + row["childlastname"],
birthday: row["childdateofbirth"],
# ...
)
end
end
请注意,您也可以使用find_or_create_by
创建子代,以避免重复。
答案 1 :(得分:0)
为了不必通过find_or_create_by逻辑对各种嵌套循环进行硬编码,我刚刚发布了一个名为 DutyFree 的gem,它使这样的导入和导出相当轻松。它可以智能地分析模型上的has_many和belongs_to关联,并基于这些关系确定如何正确地跨多个目标表保存每个导入的行。根据数据是否存在执行创建或更新。
为了从上面演示您的示例,我为John,Jessica和Josh用CSV数据编写了一个RSpec测试: https://github.com/lorint/duty_free/blob/master/spec/models/parent_simple_spec.rb
在这里可以看到更多使用相同父级和子级模型的示例: https://github.com/lorint/duty_free/blob/master/spec/models/parent_complex_spec.rb
关于这个gem的一件好事是,在配置了列定义以进行导入之后,由于所有工作都来自同一模板,因此您可以免费获得导出。对于使用CSV的示例,以下是模板,该模板允许CSV中的列名与数据库列完美对齐:
IMPORT_TEMPLATE = {
uniques: [:firstname, :children_firstname],
required: [],
all: [:firstname, :lastname, :address,
{ children: [:firstname, :lastname, :dateofbirth] }],
as: {
'parent_1_firstname' => 'Firstname',
'parent_1_lastname' => 'Lastname',
'address' => 'Address',
'childfirstname' => 'Children Firstname',
'childlastname' => 'Children Lastname',
'childdateofbirth' => 'Children Dateofbirth'
}
}.freeze
将其添加到“父模型”中,您就可以动弹了,可以调用#df_import和#df_export。