【问题标题】:CSV Upload in rails在 Rails 中上传 CSV
【发布时间】:2019-02-23 22:56:24
【问题描述】:

我正在尝试在父子表中添加父母及其子女数据。我在这些表中有现有数据,我正在尝试添加更多数据,并且我不希望重复数据。下面是我用来上传数据的代码。孩子有parent_id。

父.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

【问题讨论】:

  • find_or_update_or_create_by 定义在哪里?
  • @jvillian 它在父模型中,如上所示。
  • 请显示Parent 模型。具体来说find_or_update_or_create_by类方法的定义。
  • @jvillian 不是 Rails 中的这些内置类方法吗?我没有单独定义它们。
  • 不,find_or_update_or_create_by 不是内置的类方法。这就是为什么您会收到 undefined method 错误(正如 Pavan 所指出的那样)。

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


【解决方案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 所述),这将引发带有验证错误消息的异常。修复错误,您就可以开始了。

【讨论】:

  • 如果我尝试你在下面的建议是我得到的错误除非父级被保存,否则你不能调用 create
  • 你不能调用 create 除非父母被保存 parent.children.find_or_create_by( firstname: row['firstname'], lastname: row['lastname'], dateofbirth: row['dateofbirth'],性别:行['性别'])结束结束
  • 您可能遇到了验证错误。尝试find_or_create_by!,如果您的parent 模型出现问题,将会引发错误。
  • 它现在开始工作了。 Idk how.可能是csv数据排列不正确
【解决方案2】:

为了不必对执行 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。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-03-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-08
    • 2018-11-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多