uploading csv file to sqlite - ruby-on-rails

I am trying to upload my csv data to my sqlite table, this is my code:
require 'csv'
CSV.open('history.csv', 'r') do |row|
HistoryYear.create(:year => row[1], :first => row[2], :second => row[3], :third => row[4], :regular_season_champ => row[5])
end
I am receiving an error message, NoMethodError: undefined method '[]' for #<CSV:0x3c1fe18>. I am a new to Rails and programming in general and cannot seem to find the answer.

You need to use CSV.foreach(file...) instead
You can do something like:
require 'csv'
CSV.foreach('history.csv') do |row|
HistoryYear.create(:year => row[1], :first => row[2], :second => row[3], :third => row[4], :regular_season_champ => row[5])
end
Check out http://www.ruby-doc.org/stdlib-1.9.3/libdoc/csv/rdoc/CSV.html

Also don't forget that arrays (the rows in this case) are 0 indexed i.e. the first element of the row is row[0].

Related

How can I modify created between scope with lambda written in Rails 3.2 to Rails 4.2?

While migrating my application from Rails 3.2 to Rails 4.2, I have seen many changes, in that, scope syntax is one of the thing.
I modified all the other scopes but worried of this one:
scope :created_between, lambda { |start_at, end_at|
{ :conditions => {'users.created_at' => (start_at..end_at)} }
}
The above scope gives the users created between particular days and the related controller method code is:
def user_count
result = []
[
{:label => 'today', :start => Time.zone.now.beginning_of_day, :end => Time.zone.now.end_of_day},
{:label => 'yesterday', :start => 1.days.ago.beginning_of_day, :end => 1.days.ago.end_of_day},
{:label => 'this week', :start => Time.zone.now.beginning_of_week, :end => Time.zone.now.end_of_week},
{:label => 'last week', :start => 7.days.ago(Time.zone.now.beginning_of_week), :end => 7.days.ago(Time.zone.now.end_of_week)},
{:label => 'this month', :start => Time.zone.now.beginning_of_month, :end => Time.zone.now.end_of_month},
{:label => 'last month', :start => Time.zone.now.prev_month.beginning_of_month, :end => Time.zone.now.prev_month.end_of_month},
].each do |time_frame|
result << [time_frame[:label], User.includes(:account).only_deleted.deleted_between(time_frame[:start], time_frame[:end]).count, User.includes(:account).with_deleted.created_between(time_frame[:start], time_frame[:end]).count]
end
end
How to modify the above scope that matches the controller method with current Rails 4.2 syntax?
Rails 4.2 uses the shorter lambda style for scopes, so that will become something like:
scope :created_between, -> (start_at, end_at) {
where("? BETWEEN start_at AND end_at", 'users.created_at')
}

Rails Rake Task - How to Delete Records

I am trying to use a daily RAKE task to synchronize a users table in my app with a CSV file.
My import.rake task successfully imports records that aren't found in the table (find_or_create_by_username), but I don't know how to delete records from the table that are no longer found in the CSV file. What should I use instead of "find_or_create_by_username" to achieve this? Thanks in advance.
#lib/tasks/import.rake
desc "Import employees from csv file"
task :import => [:environment] do
file = "db/testusers.csv"
usernames = [] # make an array to collect names
CSV.foreach(file, headers: true) do |row|
Employee.find_or_create_by_username({
# Add this line:
username = row[0]
:username => username,
:last_name => row[1],
:first_name => row[2],
:employee_number => row[3],
:phone => row[4],
:mail_station => row[5]
}
)
# Collect the usernames
usernames << username
end
# Delete the employees (make sure you fire them first)
Employee.where.not( username: usernames ).destroy_all
end
You can achieve this by doing like the following:
#lib/tasks/import.rake
require 'csv'
desc "Import employees from csv file"
task :import => [:environment] do
file = "db/users.csv"
employee_ids_to_keep = []
CSV.foreach(file, headers: true) do |row|
attrs = {
:username => row[0], :last_name => row[1], :first_name => row[2],
:employee_number => row[3], :phone => row[4],:mail_station => row[5]
}
# retrieves the Employee with username
employee = Employee.where(username: attrs[:username]).first
if employee.present? # updates the user's attributes if exists
employee.update_attributes(attrs)
else # creates the Employee if does not exist in the DB
employee = Employee.create!(attrs)
end
      # keeps the ID of the employee to not destroy it
employee_ids_to_keep << employee.id
end
Employee.where('employees.id NOT IN (?)', employee_ids_to_keep).destroy_all
end
Get a list of all ID's in the database and store them in a set. Then as you do your importing, remove valid employees from the set. Once you're done, any ID's left in the set need to be removed from the database.
Something like this...
existing_ids = Employee.pluck(:id).to_set
CSV.foreach(file, headers: true) do |row|
employee = Employee.find_or_create_by.....
existing_ids.delete(employee.id)
end
Employee.destroy(*existing_ids.to_a) unless existing_ids.empty?
usernames = [] # make an array to collect names
CSV.foreach(file, headers: true) do |row|
username = row[0]
Employee.find_or_create_by_username({
:username => username,
:last_name => row[1],
:first_name => row[2],
:employee_number => row[3],
:phone => row[4],
:mail_station => row[5]
}
)
# Collect the usernames
usernames << username
end
# Delete the employees (make sure you fire them first)
Employee.where.not( username: usernames ).destroy_all
where.not will work with rails 4 of course.

'Encoding::UndefinedConversionError "\xE9" from ASCII-8BIT to UTF-8' when using some ruby gems that using file.open in ruby on rails

What's I want?
I want to generate .docx file or .odt file from template file in Rails 3.2
I want to use Japanese in it.
In ubuntu server 12.04 & ruby 1.9.3p194 & rails 3.2.8
What's happen?
I tried gems 'docx-templater' and 'serenity'
ruby-docx-templater
https://github.com/jawspeak/ruby-docx-templater
1 sample works good
2 try to do the same in my rails app
in controller as is sample
def gen_docx
input_file = './app/template/ExampleTemplate.docx'
data = {
:teacher => "Priya Vora",
:building => "Building #14",
:classroom => :'Rm 202',
:district => "Washington County Public Schools",
:senority => 12.25,
:roster => [
{:name => 'Sally', :age => 12, :attendence => '100%'},
{:name => :Xiao, :age => 10, :attendence => '94%'},
{:name => 'Bryan', :age => 13, :attendence => '100%'},
{:name => 'Larry', :age => 11, :attendence => '90%'},
{:name => 'Kumar', :age => 12, :attendence => '76%'},
{:name => 'Amber', :age => 11, :attendence => '100%'},
{:name => 'Isaiah', :age => 12, :attendence => '89%'},
{:name => 'Omar', :age => 12, :attendence => '99%'},
{:name => 'Xi', :age => 11, :attendence => '20%'},
{:name => 'Noushin', :age => 12, :attendence => '100%'}
],
:event_reports => [
{:name => 'Science Museum Field Trip', :notes => 'PTA sponsored event. Spoke to Astronaut with HAM radio.'},
{:name => 'Wilderness Center Retreat', :notes => '2 days hiking for charity:water fundraiser, $10,200 raised.'}
],
:created_at => "11-12-03 02:01"
}
DocxTemplater::DocxCreator.new(input_file, data).generate_docx_file()
end
3 but the error raised
the error raised at following point in gem (docx_templater.rb 22)
File.open(file_name, 'w') { |f| f.write(buffer) }
serenity
https://github.com/kremso/serenity
1 sample works well
2 do the same in my rails app and works well
like this
#encoding: utf-8
require 'serenity'
class Showcase
include Serenity::Generator
Person = Struct.new(:name, :items)
Item = Struct.new(:name, :usage)
def generate_showcase
#title = 'Serenity inventory'
mals_items = [Item.new('Moses Brothers Self-Defense Engine Frontier Model B', 'Lock and load')]
mal = Person.new('Malcolm Reynolds', mals_items)
jaynes_items = [Item.new('Vera', 'Callahan full-bore auto-lock with a customized trigger, double cartridge and thorough gauge'),
Item.new('Lux', 'Ratatata'),
Item.new('Knife', 'Cut-throat')]
jayne = Person.new('Jayne Cobb', jaynes_items)
#crew = [mal, jayne]
render_odt 'app/template/showcase.odt'
end
end
3 I tried my template including Japanese but the error raised.
the error raised at following point in gem(template.rb 22)
def process context
tmpfiles = []
Zip::ZipFile.open(#template) do |zipfile|
%w(content.xml styles.xml).each do |xml_file|
content = zipfile.read(xml_file)
odteruby = OdtEruby.new(XmlReader.new(content))
out = odteruby.evaluate(context)
tmpfiles << (file = Tempfile.new("serenity"))
file << out #!!!! HERE !!!!
file.close
zipfile.replace(xml_file, file.path)
end
end
end
What I did?
I found that 'serenity' have rspec test for Greek (UTF-8) in gem.I tried Japanese the same way. and the test passed!. so I thought the problem is not in gems in rails setting.
add magic comment "#encoding: utf-8" to my controller or lib file
confirm 'config.encoding = "utf-8"' in config/application.rb
add following to config/enviroment.rb above "initialize!"
Encoding.default_external = Encoding::UTF_8
Encoding.default_internal = Encoding::UTF_8
I don't use any database in my rails app.
But all is nothing to do with my case... any idea?
I may not know the basic things ...
This is a little old, but I just ran into this same situation. In my case, it was a matter of setting the tempfile to binary mode prior to writing to it:
tmpfiles << (file = Tempfile.new("serenity"))
file.binmode
file << out
file.close
Hope this helps

Convert CSV to Array?

Any ideas on how to convert this CSV into a ruby array using vim?
Starting CSV:
Year,Make,Model
1997,Ford,E350
2000,Mercury,Cougar
Desired Array:
car_info = [
{'Year' => '1997', 'Make' => 'Ford', 'Model' => 'E350'},
{'Year' => '2000', 'Make' => 'Mercury', 'Model' => 'Cougar'},
]
I have > 2000 entries like the CSV above, and I'd love a way to quickly re-format it for use in my Rails app. I'd like to use vim, but I'm open to other options too.
FasterCSV.read("path/to/file.csv", :headers => true).map do |row|
{ "Year" => row[0], "Make" => row[1], "Model" => row[2] }
end
PS: Install faster_csv gem
In vim, you can use global search and replace with a regular expression:
:g/\(.*\),\(.*\),\(.*\)/s//{'Year' => '\1', 'Make' => '\2', 'Model' => '\3'}/g
Then edit the first and last lines of the resulting file accordingly.

Get In That DB! Parsing CSV Using Ruby

I have a CSV file formatted just like this:
name,color,tasty,qty
apple,red,true,3
orange,orange,false,4
pear,greenish-yellowish,true,1
As you can see, each column in the Ruby OO world represents a mix of types -- string, string, boolean, int.
Now, ultimately, I want to parse each line in the file, determine the appropriate type, and insert that row into a database via a Rails migration. For ex:
Fruit.create(:name => 'apple', :color => 'red', :tasty => true, :qty => 3)
Help!
For Ruby 1.8:
require 'fastercsv'
FasterCSV.parse(my_string, :headers => true) do |row|
Fruit.create!(
:name => row['name'],
:color => row['color'],
:tasty => row['tasty'] == 'true',
:qty => row['qty].to_i
)
end
For Ruby 1.9, just rename FasterCSV to CSV and fastercsv to csv:
require 'csv'
CSV.parse(my_string, :headers => true) do |row|
# same as ruby-1.8
end

Resources