Home > front end >  Refactoring ruby CSV import method
Refactoring ruby CSV import method

Time:04-18

Writing out a rake task to import from csv, one would tend to write

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

But these need to be refactored taking into account a meta-structure where

Class Import  
  has_many :importattributes

The following is syntactically incorrect

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

on the line complaining about syntax error, unexpected ':', expecting 'end'
m_attr: row[sequence] If that line is commented out, other actions run as they do not parse this error beforehand.

I assume this is mistaken for the proper creation of array of attributes, because an update action, on a per attribute basis

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

does not raise the error.

CodePudding user response:

This is not a valid syntax m_attr: row[sequence]. When used as an argument for update it is treated as a hash { m_attr: row[sequence] } and curly brackets can be omitted.

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 accepts a hash of attributes to create a single record or an array of hashes to create multiple records. The return value of the import logic has to be one of these two options. For clarity, it can be done in three steps:

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)

or in one step using inject

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