I have 3 models, Church, which has many Locations, which has many Pastors.
require 'csv'
csvfile = File.read("testimport.csv")
csv = CSV.parse(csvfile, :headers => false)
csv.each do |row|
c = Church.new
c.name = row[0]
c.url = row[10]
c.locations.build(:address => row[3], :zipcode => row[5], :phone => row[6], :email => row[2], :city => row[4])
c.save
end
As you can see in my short block of code I am creating a Church and its first location. How would I also add a pastor to that?
For instance will this work?
require 'csv'
csvfile = File.read("testimport.csv")
csv = CSV.parse(csvfile, :headers => false)
csv.each do |row|
c = Church.new
c.name = row[0]
c.url = row[10]
location = c.locations.build(:address => row[3], :zipcode => row[5], :phone => row[6], :email => row[2], :city => row[4])
location.pastors.build(:name => row[10])
location.save
c.save
end
Is there another way I should be going about this? Trying to move thousands of records from one rails app to another.
I take a slightly different approach to this, I have found a two step process is easier to use and build on.
The first step is load the data.
I use two 'staging' tables.
Something like:
staging_header
id Integer Unique Primary Key
run_number Integer Unique
run_name String
staging_data:
id Integer Unique Primary Key
staging_header_id Integer
element1 String
element2 String
element3 String
uploaded? Boolean # Placed on the individual records allows restarts.
...
So I load the testimport.csv directly into these loading tables - which support multiple runs if you make the run_number unique (sequence, etc.)
Now you have the data in sql and available in rails.
Now write the code to actually populate the application tables from this loading area.
This will also help you with the speed issue. Rails will only be inserting a few records per second, so you want to be able to do restarts, pauses, etc.
This will also help with validation. Initially you just want to load the data, regardless of any constraints (not null, unique, etc.).
Once loaded into staging you can be more selective and apply validations as you wish.
I was able to get this to work, the following is what I used. Let me know if there is a smarter way to do this. NOTE: if you are trying to do this, place the csv file in the root of your rails directory and execute this script line by line in the console. At least thats how I got it working.
require 'csv'
csvfile = File.read("testimport.csv")
csv = CSV.parse(csvfile, :headers => false)
csv.each do |row|
c = Church.new
c.name = row[0]
c.url = row[10]
c.locations.build(:title => "Sanctuary", :address => row[3], :zipcode => row[5], :phone => row[6], :email => row[2], :city => row[4])
c.save
loc = c.locations.first
loc.pastors.build(:firstname => row[1])
loc.save
end
Related
I'm using the Gem active_hash https://github.com/zilkey/active_hash to create models for simple data that I don't want to create DB tables for.
For example, I have this model setup for FieldTypes:
class FieldType < ActiveHash::Base
self.data = [
{:id => 1, :name => "text", :friendly_name => "Text"},
{:id => 2, :name => "textarea", :friendly_ => "Text Area"},
{:id => 3, :name => "image", :friendly_ => "Image"},
]
end
And I'm trying to list these field types for a select:
def field_types_for_select
#FieldType.all.order('name asc').collect { |t| [t.friendly_name, t.name] }
FieldType.pluck(:friendly_name, :name)
end
But I get an error that order, collect or pluck are not defined.
How do I access this data? This works fine on other models, just not ActiveHash ones. According to the docs the model should work the same as ActiveRecord but I don't seem to be able to access it the same. FieldType.all works, but other methods do not.
Pluck isn't defined on ActiveHash::Base. It is defined on ActiveRecord::Relation::Calculations, and it's purpose is to produce a SQL select for the columns you specify. You will not be able to get it to work with ActiveHash.
You can, however, define your own pluck on your FieldType model.
def self.pluck(*columns)
data.map { |row| row.values_at(*columns) }
end
Or query the data directly:
FiledType.data.map { |row| row.values_at(:friendly_name, :name) }
Firstly, I'm really sorry to ask such a basic question but I'm very new to Rails, Ruby & development in general and my lack of terminology understanding means that I am having a hard time finding the answer to this question.
I am importing a csv of vehicle data using:
def self.import(file, category_id)
CSV.foreach(file.path, headers: true) do |row|
Model.where(
:category_id => category_id,
:name => row[1],
:cap_id => row[10]
).first_or_create do |record|
record.layout = row[3],
... several records later ...
record.manufacturer_id = Manufacturer.where(:name => row[0], :category_id => category_id).id
end
end
end
but I am having trouble setting the manufacturer_id with the last line of the loop. I guess you can see what i'm trying to do here but I can't work out how this should be written.
Basically i have a list of manufacturers belonging to different categories (so, for example, there is a Ford manufacturer with category_id=1 (for cars) and another Ford manufacturer with category_id=54 for trucks.
Can I set the manufacturer_id of each record by taking the current category_id and the manufacturer name from the csv, cross referencing them and pulling back the id of the result?
When trying the above code i get the following error:
NoMethodError in ModelsController#import
undefined method `id' for #<ActiveRecord::Relation::ActiveRecord_Relation_Manufacturer:0x007fcd96f744a8>
Extracted source (around line #33):
32 record.description = row[2],
33 record.manufacturer_id = Manufacturer.where(:name => row[0], :category_id => category_id).id
34 end
35 end
36 end
The following line of code returns an ActiveRecord::Relation object
Manufacturer.where(:name => row[0], :category_id => category_id)
so when you called id on it, it raised an error. You should call first first and then id.
Manufacturer.where(:name => row[0], :category_id => category_id).first.id
Be warned that doing so assumes that you'll always get a manufacturer that matches the condition. To be more safe, you can use try
Manufacturer.where(:name => row[0], :category_id => category_id).first.try(:id)
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
I have state data in a txt file that I used to seed my States db which has columns :id and :name. the :name is the state 2-digit code. Used the following code in seeds.rb file:
State.delete_all
open("C:/Sites/rails_projects/sales_tracking/lib/assets/states.txt") do |states|
states.read.each_line do |state|
name = state
State.create!(:name => name)
end
end
I now have my Cities.txt file with data of city,state. My cities db has columns :id, :name, :state_id. :state_id is the foreign key from the states table. What code do I need to add to the below part of my seeds.rb file to populate the :state_id while running rake db:seed on the city seed data ("code" is 2-digit state id).
City.delete_all
open("C:/Sites/rails_projects/sales_tracking/lib/assets/cities.txt") do |cities|
cities.read.each_line do |city|
name, code = city.chomp.split(",")
??
City.create!(:name => name, :state_id => state_id)
end
end
Use a dynamic finder to get the state:
City.create!(:name => name, :state => State.find_by_name(code))
Or if you'd like to avoid a few queries, and if the state code is guaranteed to exist, you can keep track of the states as you seed them in a hash and reuse them for the cities:
State.delete_all
City.delete_all
#states = {}
open("states.txt").read.each_line do |code|
#states[code] = State.create!(:name => code)
end
open("cities.txt").read.each_line do |city|
name, code = city.chomp.split(",")
City.create!(:name => name, :state => #states[code])
end
I have a join table, which have 3 parameters. I want to update it, using a where-clause, something like this: (which obviously is not correct)
Grid.update(:page_id => #page_id,:thing_id => #thing_id,:number => #number ).where(:page_id => #page_id, :number => #number ).first
I need to find the record with mathing page_id and number, and then update the thing_id.
Thanks!
Jakob
Grid.where(:page_id => #page_id, :number => #number).first.
update_attributes(:page_id => ...,: thing_id => ..., :number => ...)