上传CSV文件时出现“未知属性”错误

时间:2017-09-23 00:44:29

标签: ruby-on-rails csv controller

以下是我尝试上传的CSV文件:

1,Order,”{‘customer_name’:’Jack’,’customer_address’:’Trade St.’,’status’:’unpaid’}”
2,Order,”{‘customer_name’:’Sam’,’customer_address’:’Gecko St.’,’status’:’unpaid’}”
1,Product,”{‘name’:’Laptop’,’price’:2100,’stock_levels’:29}"
1,Order,”{‘status’:’paid’,’ship_date’:’2017-01-18’,’shipping_provider’:’DHL’}”
2,Product,”{‘name’:’Microphones’,’price’:160,’stock_levels’:1500}"
1,Invoice,”{‘order_id’:7,’product_ids’:[1,5,3],’status’:’unpaid’,’total’:2500}"
1,Invoice,”{‘status’:’paid’}”

但我收到此错误:ActiveModel::UnknownAttributeError

中的CustomersController#import

我的控制台中存在以下错误:

app/models/customer.rb:4:in `block in import'
app/models/customer.rb:3:in `import'
app/controllers/customers_controller.rb:65:in `import'

这是我的customer.rb模型:

class Customer < ApplicationRecord
  def self.import(file)
    CSV.foreach(file.path, headers: true) do |row|
      Customer.create! row.to_hash
    end
  end
end

说实话,我在这里遇到的部分问题源于并不完全理解row.to_hash在这里所做的事情。如果此函数不迭代一行,那么我们希望将其转换为散列。我觉得这可能会引起其他问题,但我可能并不知道。

这是我的导入功能:

def import
  Customer.import(params[:file])
  redirect_to customer_path, notice: "Customer Added Successfully"
end

1 个答案:

答案 0 :(得分:0)

如果您将模型没有的属性传递给ActiveModel::UnknownAttributeErrornew,则会发生错误create,例如:

User.create(not_a_real_attribute: 'some value')
# => ActiveModel::UnknownAttributeError: unknown attribute 'not_a_real_attribute' for User.

您之所以如此,是因为您使用的是无标题CSV,就好像它有标题一样。在ruby中,如果CSV具有标题,则可以使用列的标题作为键并将当前行的列作为值将行转换为散列。因此,通过告知CSV库您有标题(通过headers: true中的foreach),它会将第一行视为标题行,并最终产生奇怪的结果:

enum = CSV.foreach("./customers.csv", headers: true)
enum.first.to_hash
# => {"1"=>"2", "Order"=>"Order", "”{‘customer_name’:’Jack’"=>"”{‘customer_name’:’Sam’", "’customer_address’:’Trade St.’"=>"’customer_address’:’Gecko St.’", "’status’:’unpaid’}”"=>"’status’:’unpaid’}”"}

然后您将该哈希传递给Customer.create!。如果您不期望标题,则需要将每一行视为数组:

enum = CSV.foreach("./customers.csv")
enum.first
# => ["1", "Order", "”{‘customer_name’:’Jack’", "’customer_address’:’Trade St.’", "’status’:’unpaid’}”"]

或者,如果您想使用哈希,可以插入更好的第一行,对应于模型的属性:

"Maybe an ID?","Some kind of Class?","Customer Data?"
1,Order,”{‘customer_name’:’Jack’,’customer_address’:’Trade St.’,’status’:’unpaid’}”
# ... the rest of your file ...

enum = CSV.foreach("./customers.csv", headers: true)
enum.first.to_hash
# => {"Maybe an ID?"=>"1", "Some kind of Class?"=>"Order", "Customer Data?"=>"”{‘customer_name’:’Jack’", nil=>"’status’:’unpaid’}”"}

在这些示例中,您还会注意到,文件中的特殊引号未得到正确处理,如果将这些引号更改为正常引号,则会得到以下结果:

# => {"Maybe an ID?"=>"1", "Some kind of Class?"=>"Order", "Customer Data?"=>"{'customer_name':'Jack','customer_address':'Trade St.','status':'unpaid'}"}

此外,如果最后一列是您要创建的客户数据,则需要将该列拉出并将其解析为您自己的ruby哈希值。看起来像是YAML?:

YAML.load enum.first.to_hash['Customer Data?']
# => {"customer_name"=>"Jack", "customer_address"=>"Trade St.", "status"=>"unpaid"}
相关问题