ActiveRecord `from_csv` method - howto make it more sexy?

783 Views Asked by At

I have written method to load data to DB from CSV. For me it's a little bit unsexy and it's far away from DRY:

  def self.from_csv(data)
    c = Company.new
    FasterCSV.parse(data) do |row|
      c.name = row[0]
      c.street = row[1]
      c.street_number = row[2]
      c.apartament_number = row[3]

      c.city = row[4]
      c.post_code = row[5]
      c.post_office_city = row[6]

      c.nip = row[7]
      c.regon = row[8]
      c.vatin = row[9]
    end
  end

How to make it more sexy or may be there is already any lib to load data?

3

There are 3 best solutions below

1
Simon Perepelitsa On BEST ANSWER

You can put a sexy lady on top of it:

#          ___
#   _  _.-"_< }
#    ""--"" 7(
#          /())
#         / )/
#        ^ ( \
#          / /
#         /.'
#        //
# ______/L___ sexii
def self.from_csv(data)
  #...
end

But, seriously, the only problem I see with your code is that you cannot rearrange attributes easily because you will have to manually update all indexes. I'd prefer to have an ordered list of attributes in an array and use some Ruby's dynamic method calling:

def self.from_csv(data)
  company = new
  row = CSV.parse_line(data)
  [:name, :street, :street_number, :apartament_number,
   :city, :post_code, :post_office_city,
   :nip, :regon, :vatin].each_with_index do |name, i|
    company.send(:"#{name}=", row[i])
  end
  company
end

Also note that you need to return a constucted company instance at the end otherwise you will get some random value when calling Company.from_csv.

0
Prair On
c = Company.new
cols = ["name", "street", "street_number", "apartament_number", "city", "post_code", "post_office_city", "nip", "regon", "vatic"]

FasterCSV.parse(data) do |row|
  cols.each_index { |i| c.send("#{cols[i]}=", row[i]) }
end
3
tee On

I wrote this lightweight wrapper to load CSV files:

https://github.com/stackpilot/loady

It works with ruby 1.9 and uses the standard ruby CSV library (formerly known as FasterCSV).

You do this with it:

Loady.csv "/your/file.csv" do |row|
  Company.create row.to_attributes [:name, :street, :street_number, ...]
end