Rails Rake Task - How to Delete Records - ruby-on-rails

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.

Related

Override Rails Uploader to seed database

I have a CarrierWave rails uploader. I want to seed the database with fake users so I'm trying to add the images in with the same seed file. The images are in a common storage, so if I can just get the avatar strings in the database they'll work. When it saves the users though the image's aren't sticking.
# db/seeds.rb
user1 = User.create :email => "test1#test.com", :password => "testing", :name => "Bob Dylan", :avatar => "v1357014344/bdylan.jpg"
user1.save
# IRB
User.first
=> #<User id: 1, email: "test1#test.com", name: "Bob Dylan", avatar: nil>
> a = User.first
> a.avatar = "v1357014344/bdylan.jpg"
> a.save
(10.7ms) commit transaction
=> true
> a
=> #<User id: 1, email: "test1#test.com", name: "Bob Dylan", avatar: nil>
You will have to insert the data in the following way.
File.open(File.join(Rails.root, 'test.jpg'))
So the entire user create would look like
User.create :email => "test1#test.com", :password => "testing", :name => "Bob Dylan", :avatar => open("v1357014344/bdylan.jpg")
Related question
Besides using open() as Nishant suggestions, you can also specify remote_avatar_url to manually set the remote URL.
User.create :email => "test1#test.com", :password => "testing", :name => "Bob Dylan", :remote_avatar_url => "http://upload.wikimedia.org/wikipedia/commons/2/28/Joan_Baez_Bob_Dylan_crop.jpg"
Thanks to JosephJaber for suggesting this in Seeding file uploads with CarrierWave, Rails 3
I used this approach to populate some video URLs for CarrierWave Uploader in my seeds.rb
To update the database directly and skip out on CarrierWave:
model[:attribute] = 'url.jpg'
model.save

'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

uploading csv file to sqlite

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].

how to import data into rails?

I have a Rails 3 application with a User class, and a tab-delimited file of users that I want to import.
How do I get access to the Active Record model outside the rails console, so that I can write a script to do
require "???active-record???"
File.open("users.txt", "r").each do |line|
name, age, profession = line.strip.split("\t")
u = User.new(:name => name, :age => age, :profession => profession)
u.save
end
Do I use the "ar-extensions" gem, or is there another way? (I don't particularly care about speed right now, I just want something simple.)
You can write a rake method to so.
Add this to a my_rakes.rake file in your_app/lib/tasks folder:
desc "Import users."
task :import_users => :environment do
File.open("users.txt", "r").each do |line|
name, age, profession = line.strip.split("\t")
u = User.new(:name => name, :age => age, :profession => profession)
u.save
end
end
An then call $ rake import_users from the root folder of your app in Terminal.
Use the activerecord-import gem for bulk importing.
Install via your Gemfile:
gem 'activerecord-import'
Collect your users and import:
desc "Import users."
task :import_users => :environment do
users = File.open("users.txt", "r").map do |line|
name, age, profession = line.strip.split("\t")
User.new(:name => name, :age => age, :profession => profession)
end
User.import users
end

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