There's a lot going wrong here so I'll start at the top.
CSV.foreach
is meant to open a file and iterate over it all at once. The first argument to CSV.foreach
should be a file name not the file's content. That means that this:
CSV.foreach(file, :headers => true) do |row|
goes wrong because file
is a string containing the CSV data rather than the file name that CSV.foreach
expects. Since you're converting from Latin-1 text to UTF-8, you'll want to get CSV.foreach
to deal with that for you and you can use the :encoding
option for that:
This method also understands an additional
:encoding
parameter that you can use to specify the Encoding of the data in the file to be read. [...] For example,encoding: "UTF-32BE:UTF-8"
would read UTF-32BE data from the file but transcode it to UTF-8 before CSV parses it.
Putting that together, we have:
CSV.foreach('filepath of my csv', :headers => true, :encoding => 'ISO-8859-1:UTF-8') do |row|
Once you get the CSV reading and iteration going, you'll see errors like:
NameError: undefined local variable or method `product' for ...
You'd get a NameError
because there is no product
defined anywhere in your rake task. I suspect that you mean to say Product.create
, that would try to create a new instance of your Product
model. Ruby is case sensitive so product
and Product
are different things and Product
would be the class.
Once the NameError
is dealt with, you'll see complaints like this:
NoMethodError: undefined method `keys' for [{ ... }]:Array
You'll get the NoMethodError
because Product.create
wants to see a Hash of attributes and their values, not an Array which contains a Hash. You would want to say:
Product.create(
:name => row['name'],
:rating => row['rating'],
:year => row['year'],
:country => row['country'],
:state_or_province => row['state_or_province']
)
Of course, if your row
contains only those five values, then just hand the whole row
to create
:
Product.create(row.to_hash)
and if row
contains (or might contain) a bunch of other stuff that you don't want create
to see, use Hash#slice
to grab just the part of row
that you're interested in:
Product.create(row.to_hash.slice(*%w[name rating year country state_or_province]))
Note that %w[...]
builds an array of strings from a white-space delimited list so these are the same:
%w[a b]
['a', 'b']
Then the splat (*
) removes the array wrapper so these are the same:
row.to_hash.slice(*%w[name rating year country state_or_province])
row.to_hash.slice('name', 'rating', 'year', 'country', 'state_or_province')
You can use whichever form is easier on your eyes.
Also note the to_hash
calls in there. Your row
will be a CSV::Row
object, calling to_hash
on it will give you the row as a Hash.
That should leave your entire rake task looking like this:
CSV.foreach('filepath of my csv', :headers => true, :encoding => 'ISO-8859-1:UTF-8') do |row|
Product.create(row.to_hash)
end
or
CSV.foreach('filepath of my csv', :headers => true, :encoding => 'ISO-8859-1:UTF-8') do |row|
Product.create(row.to_hash.slice(*%w[name rating year country state_or_province]))
end
You might want to add some error handling to those create
calls too.