Saturday, May 31, 2008

transaction.records.create!(row.to_hash)

This one I really like:

transactions.records.create!(row.to_hash)

But now I have a problem. Is this where I indicate what table I want my csv file imported to? I used the word transactions and maybe should use a different one not to be confused with the .transaction class method.

Note my table name is plural... Should I use the plural here?

(row.to_hash)

James told me this magic allows me not to have to specify a hash for all my columns that I want to import into my database table. If I did not have this I would have to do this:

transactions.records.create!(:date => date, :amount => amount, :card_id => card_id

If I had a ton of columns this would hard to do... Also James said that in order for this row.to_hash to work you need to have headers set to true or specify the headers in the block or it will complain.

do |row|

Now comes the part where the action happens...

do |row|



:headers => true,

This one I get...

:headers => true,

This tells the FasterCSV that the file you are uploading has headers. So that answers one of the questions. If you don't have headers it is :headers => false

FasterCSV.foreach...

This is the FasterCSV statement


FasterCSV.foreach("csv_test/public/csv/test_copy.csv",

for reading the file line by line. You can read about it here:

http://fastercsv.rubyforge.org/

I decided to start simple because I was having trouble understanding the code to make the import work from HTML. Once I get this to work I will work on getting the import file to work.

begin

Now for the begin statement:

begin
Record.transaction do

The Record.transaction do is nice and descriptive and tells the app that we want to record a transaction... right? Well, I would think so... breaking this up we see that Record is a class (because it starts with a Capitalization... ) But I have not defined Record anywhere so it must be a built in class in Ruby... I have searched for it but cannot find it... any help here?

The .transaction I did find out and is explained pretty well here:
http://api.rubyonrails.org/
by going to the file:
vendor/rails/activerecord/lib/active_record/transactions.rb

in a nutshell we are using .transaction because we want the insert to our database to be done only if the whole insertion succeeds. Thats why transaction is called a protective block... If it does not succeed then we can role the transaction back... no harm.

3. Import Controller code (FasterCSV)

So now for the real code.


The FasterCSV code I received from emailing James Edward Gray II who was nice enough to get me started on working on this...

I am going to break this code apart in bits in subsequent posts and hopefully get a better understanding about what is going on with comments from others...

Here is my first attempt:

class ImportController < ApplicationController
require 'fastercsv'

def index
end

def csv_import

begin
Record.transaction do
FasterCSV.foreach("csv_test/public/csv/test_copy.csv",
:headers => true)
do |row|
transactions.records.create!(row.to_hash)
end
end

flash[:notice] = "Successfully added."
redirect_to 'index'
rescue
#do something with the error
flash[:error] = "error adding. Please try again."
redirect_to '/import/index'
end

end

end

2. Creating the csv_test app

So for the app... I am going to call it csv_test so I get going:

>rails --d mysql csv_test
# I specify mysql bc the mac keeps creating sqlite and I like mysql better (i think)


#stuff gets created

>rake db:create

#this creates my databases...

>ruby script/generate controller import

#creates my controller

>ruby script/generate model transaction

#I create a transaction model mainly because I want to create my transaction table this gives me the file : 001_create_transactions. I open this and add the following items for my table:

class CreateTransactions < ActiveRecord::Migration
def self.up
create_table :transactions do |t|
t.datetime :date
t.integer :amount
t.integer :card_id

t.timestamps
end
end

def self.down
drop_table :transactions
end
end

#So its a simple table that has three columns :date, :amount, :card_id. These will hopefully correspond to my csv file I am trying to import.


Here are the contents of my data file - test.csv:

date, amount, card_id
5/06/2008, 20, 1234
06/05/2008, 50, 1235
10/30/2008, 45.45, 1342

I have a date, amount and a card_id just like my database table. Pretty simple.

Tuesday, May 27, 2008

1. Rails and FasterCSV Intro...

This is my attempt to use the FasterCSV plugin for rails. I am a very begin, begin again, programmer so it is my hope the some of this is true and others can point out whats wrong with the code:

Ok the problem:

To import a csv file (thats a comma delimited file) into a database (mysql for me) table.

Pretty simple task but if you don't know it all kinds of things crop up like:
How do I get the file in there?
How does it know where to map the data?
How do I not import the headers or blanks?

I have been emailing back and forth with a James Edward Gray II who wrote the FasterCSV in the first place and I hope that he can comment here so I can make this a working example for all to see.

Also I don't know how this is going to work on blogger but this is my easiest way to publish currently.