重构ruby CSV导入方式

Refactoring ruby CSV import method

编写一个从 csv 导入的 rake 任务,人们往往会这样写

Article.create(
   category_id: row[0],
   label: row[1],
   name: row[2],
   integer: row[3],
   priority: row[4]
)

但是这些需要重构,考虑到元结构,其中

Class Import  
  has_many :importattributes

以下语法不正确

Article.create(
  import.importattributes.each do |importattribute|
    m_attr = importattribute.mapped_attribute
    sequence = importattribute.position.to_i
    m_attr: row[sequence]
  end
)

在线投诉syntax error, unexpected ':', expecting 'end'
m_attr: row[sequence] 如果该行被注释掉,其他操作 运行 因为它们不会事先解析此错误。

我认为这被误认为是正确创建属性数组,因为更新操作是基于每个属性

import.importattributes.each do |importattribute|
  m_attr = importattribute.mapped_attribute
  sequence = importattribute.position.to_i
  Article.update(m_attr: row[sequence])
end

不会引发错误。

这不是有效的语法 m_attr: row[sequence]。当用作 update 的参数时,它被视为散列 { m_attr: row[sequence] } 并且大括号可以省略。

Article.create(
  import.importattributes.each do |importattribute|  # returns `import.importattributes`
                                                     # and used as argument for `create`
                                                     # nothing from `each` block is used

    m_attr = importattribute.mapped_attribute        # `m_attr` is unused

    sequence = importattribute.position.to_i

    m_attr: row[sequence]                            # invalid syntax
    # at the very least it has to be wrapped in {} and used with hashrocket syntax
    # to make use of m_attr variable.
    # { m_attr => row[sequence] }
  end                                                
)

create 接受属性散列以创建单个记录或接受散列数组以创建多条记录。导入逻辑的 return 值必须是这两个选项之一。为了清楚起见,可以分三步完成:

attributes = {}

import.importattributes.each do |importattribute|
  attribute_name = importattribute.mapped_attribute 
  csv_column     = importattribute.position.to_i
  attributes[attribute_name] = row[csv_column] }
end

Article.create(attributes)

或一步使用 inject

Article.create(
  import.importattributes.inject({}) do |attributes, importattribute| 
    attributes[importattribute.mapped_attribute] = row[importattribute.position.to_i] 
    attributes
  end
)