Upload and import data from CSV file in Rails application? - ruby-on-rails

I am new to Ruby on Rails.
I want to write a module for uploading a CSV file in my application. Also, I want to import the data from that file to one of my tables in my Rails application.
In my application there is a model named "Book" which has four fields: name, author, publication_date and publisher_name.
I want to give user the ability to upload a CSV file with the format:
first column for name
second column for author
third for publication_date
fourth for publisher_name.
Also I want to add the validation so that upload will happen only when the file is of the expected format.

You need a FasterCSV gem to do that.First install it and later in your model do like this:
require 'csv'
validates_format_of :book, :with => /^.+\.(csv)$/,
:message => 'A .csv file is required.'
records = CSV.foreach('yourpath/tocsvfile/filename.csv').map do |row|
Book.create!({
:name => row[0],
:author => row[1],
:publication_date => row[2],
:publisher_name => row[3],
})
end
For more information about CSV,you can find it here
Hope it Helps!

Related

Rails to excel with associations

i'am new on rails , i've spent my day looking for solution to export my data into excel file.
I've tryed to_xls, simple_xlxs and other gems, also i've tryed to render xml template , but i've no success.
So i have associations between 2 models:
Call model:
class Call < ActiveRecord::Base
belongs_to :number
has_many :results
end
and my result model:
class Result < ActiveRecord::Base
belongs_to :call
end
So i need to genrate excel tables with my OWN headers in table calle'd as i want.
And also i wan't that in this excel file will be columns from my associeted model
What can i do?
Thanks
# install in a gem file or in the terminal to test
# gem install spreadsheet
require 'spreadsheet'
Spreadsheet.client_encoding = 'UTF-8'
book = Spreadsheet::Workbook.new
sheet1 = book.create_worksheet :name => 'test'
money_format = Spreadsheet::Format.new :number_format => "#,##0.00 [$€-407]"
date_format = Spreadsheet::Format.new :number_format => 'MM.DD.YYYY'
# set default column formats
sheet1.column(1).default_format = money_format
sheet1.column(2).default_format = date_format
# depending on your data you obviously have to create a loop that fits the format of your data
sheet1.row(0).push "just text", 5.98, DateTime.now
book.write 'sample.xls'
The above code example writes the data to columns you create. You can have your info in csv style. So if you're returning objects you can just get values for each object and join the array with ',' separation and loop through.

populate random data in ruby on rails

I need help in populate some random data in my database table.
I have a list of 10 users in my system. My allergy table has the following fields:
id user_id name reactions status
I have the following allergies hash in a variable called allergy_hash.
{:reaction_name=>"Bleeding", :status=>"Death", :name=>"A"} {:reaction_name=>"Nausea", :status=>"Serious", :name=>"B"} {:reaction_name=>"Fever", :status=>"Death", :name=>"C"} {:reaction_name=>"Blistering", :status=>"Serious", :name=>"D"}
Here is what I have done so far:
def create_random_data
users.each do |user|
allergies.each do |allergies_hash|
Allergy.where(user_id: user.id).first_or_create(
allergies_hash )
end
end
end
What the above does is just inserts Bleeding, Death and A into the table for all users 1 to 10.
But I need to insert such that different users can have different values. Also some users can have more than one allergy and the associated reactions.
NOTE: I do not mean completely random. For example name 'A' should still have the associated status 'Death' and reaction_name 'Bleeding'.
Name 'B' should have the associated status 'Serious' and reaction 'Nausea'in the allergy table.
When creating the users, use sample on allergies_hash = [{:reaction_name=>"Bleeding", :status=>"Death", :name=>"A"}, {:reaction_name=>"Nausea", :status=>"Serious", :name=>"B"}, {:reaction_name=>"Fever", :status=>"Death", :name=>"C"}, {:reaction_name=>"Blistering", :status=>"Serious", :name=>"D"}]
Allergy.where(user_id: user.id).first_or_create(allergies_hash.sample)
UPDATE
I'll loop through the users instead, so for each user you attempt to add from 1 to 3 allergies from your allergies_hash
User.all.each do |user|
[1,2,3].sample.times do
user.allergies.where(allergies_hash.sample).first_or_create
end
end
I would recommend you to check Faker and Factory girl to populate some random data.
You can either seed data into your app by going to the seed file in the app/db directory
and do something like this
User.delete_all
Bill.delete_all
u1 = User.create(:email => "bob#aol.com", :password =>"a", :password_confirmation => "a")
b1 = Bill.create(:name => "rent", :description => "the rent", :amount => 10_000, :day => 1)
b2 = Bill.create(:name => "cable", :description => "the cable", :amount => 150, :day => 5)
or you can also use the Faker gem to generate fake data.
http://geekswithblogs.net/alexmoore/archive/2010/01/18/faker-gem---a-quick-and-dirty-introduction.aspx

Rails Seed with nested creation

I've created a bunch of models for an app I'm working with, and I want to seed them using the seeds.rb file. Problem is, I've nested the creation of one model inside the other (not sure how else to say that), such that when an "Animal" is created, it should automatically create a set of "Packages."
To illustrate, this is in my animal.rb file (details unimportant -- it's just building a set of packages based on the input animal data):
after_create :create_packages
def create_packages
#cut_list = Cut.where(:animal_type => self.animal_type)
#cut_list.each do |c|
Package.create!(:animal_id => self.id, :cut_id => c.id,
:original => (self.weight * (c.percent)/100) / c.package_weight,
:left => (self.weight * (c.percent)/100) / c.package_weight)
end
end
In other words, packages, which belong_to animals, are auto-created when an animal is created -- if the animal is created on my app. With the seed, however, just doing this:
Animal.create(
:name => 'Donald Trump',
:animal_type => "Pig",
:breed => "Hungarian",
:weight => 800,
:farm => "The Piggie Farm",
:photo => "NA"
)
doesn't build out the associated packages, and since I've built display of packages into my animals show pages, if I reset the db and run an animals/# page, I get an error suggesting that no packages exist for their attributes to be displayed.
Is there any way to get seed data to automatically generate its associated data (that is, to literally call my create method and follow the after_create command), so that I don't have to manufacture seed data for all of the packages that should be auto-generated?
Thanks.

Can't convert BSON::ObjectId into String

So........ I have a rails app. The rails app uses Mongoid for mongodb data. When I create mongo records through web forms, they have IDs with type string. When I import records into mongo using mongoimport, they have IDs with type BSON::ObjectId.
The rails app is expecting the mongo record IDs to be strings, and therefore when I import the data, it causes my app to fail because when it looks up the records it complains that it can't convert type BSON::ObjectId to string
I'm confused on a number of levels here. BSON::ObjectId is the default type for IDs in mongo, so I don't understand why the records created through rails and Mongoid have string IDs. I don't see anywhere where Mongoid is specifying that the _id field should be a string. Does anybody have any clues?
What version of Mongoid are you using? From this post, it looks like Mongoid was using strings up until a year ago for _id's but now consistently uses the BSON::ObjectId type.
mongodb: converting object ID's to BSON::ObjectId
It references this gist for converting old documents with String _id's to using BSON::ObjectId type _id's.
When Mongoid inserts a document into a collection, it expects and uses the BSON::ObjectId type. This is an example using the Rails console:
post = Post.new
=> #
post.save
=> true
post._id
=> BSON::ObjectId('4ff5bcb39ef1728393000002')
post._id.class
=> BSON::ObjectId
Mongoid appears to know to look up _id's using the BSON::ObjectId type:
Post.where(:_id => "4ff5bcb39ef1728393000002").count
=> 1
Post.where(:_id => BSON::ObjectId("4ff5bcb39ef1728393000002") ).count
=> 1
Are you, by any chance, manually setting the _id's? If you are, then perhaps you're not setting the _id's as BSON::ObjectId types.
About your last paragraph: MongoDB's specification is expecting for 12 byte string.
So I figured it out. The issue is with the version of Mongoid that is used by my application. Version 1.9.5 uses strings as the default type for the _id field, which is what I'm using.
I thought about updating Mongoid, but I was afraid that the old string IDs would somehow break the application.
The answer was to somehow import the records using the rails app, so that the old version of Mongoid would be in charge of inserting the records. I created a rake task that would parse the CSV file and insert the records from that file within my app environment.
require 'csv'
require 'iconv'
namespace :deadline do
desc "Import data from CSV file"
task :import => :environment do
CSV.parse(File.open("/tmp/deadlines.csv").read).map{ |row|
app_deadline = OrgSpecific::ApplicationDeadline.create!(
:name => row[2] + " " + row[3],
:start_date => Date.strptime('1/1/2012', '%m/%d/%Y'),
:deadline_date => Date.strptime(row[11], '%m/%d/%Y'),
:term => row[2],
:year => row[3],
:comment => Iconv.conv("UTF8", "LATIN1", row[5]) + " : " + Iconv.conv("UTF8", "LATIN1", row[6])
)
}
end
end
And voila! All the data from my CSV file has been imported through my rails environment, meaning that my mongo records have an _id of type string. Thanks for the help guys!

How can I load DataMapper objects in an SQLite database with data from a spreadsheet?

I have Ruby on Rails app using DataMapper, the database is SQLite, the app is hosted on Heroku. I would like to load the DataBase with data from a spreadsheet, however, I don't know the most efficient way...please help!
As an example, let say I have a User model with fields:
Name
Age
Birthday
Hometown
I had a similar problem of importing external data into datamapper. I did a CSV dump of the data from the external database, then wrote an import which read the CSV and create a new record.
class Staff
include DataMapper::Resource
property :id, String, :key => true
property :full_name, String
property :email, String
has n, :stages
end
Then:
CSV.parse(staff) do |row|
#staff = Staff.create(
:id => row[1],
:full_name => row[0],
:email => row[0].downcase.gsub!(' ', '.')
);
#staff.save
Perhaps an approach like this would be suitable?

Resources