migrate data in rails when deploying - ruby-on-rails

I have two tables I want to populate with data - countries, and cities. The user doesn't add/update these tables. I want them to be part of a migration so when I deploy to Heroku the data is transferred too. Up until now, I've only been migrating structure (not data). Is this possible?

Yes it is possible. Populate your initial data in db/seeds.rb like this:
Country.create(name: 'Germany', population: 81831000)
Country.create(name: 'France', population: 65447374)
Country.create(name: 'Belgium', population: 10839905)
Country.create(name: 'Netherlands', population: 16680000)
and do rake db:seed in production to load data from your seeds.
Tutorial.

As emaillenin said those data are seeds, anyway you can use a migration if you want, nothing difficult:
class ImportCountriesAndCities < ActiveRecord::Migration
def self.up
import_countries_and_cities
end
def self.down
remove_countries_and_cities
end
private
def self.import_countries_and_cities
..
end
def self.remove_countries_and_cities
...
end
end

Related

I have to migrate data from one column to an other in same table but have to add a prefix in all the records. in rails DB migration

I am migrating records from one column to other in same table in rails, using SQL DB. I have to set a prefix with all the migrated records.
Finally I managed to migrate data from one column to another with a prefix.
class MigrateOldFiledata < ActiveRecord::Migration[5.1]
def self.up
execute "update table_name set new_column = concat('prefix', '/',
old_column)"
end
def self.down
end
end

How to use exist database?

I have a exist web application build by PHP.
Now i need to rebuild this application by Rails.
I already have this following data in database:
--------------------------------------------------
| user_id | user_name | .....
--------------------------------------------------
| 1 | david | .....
--------------------------------------------------
| 2 | jobs | .....
--------------------------------------------------
I use this following command to generate User model:
rails g model User
And i type columns into User migration file manually:
create_table :users do |t|
t.string :user_name
...
...
t.timestamps
end
Then i try to use following command to read data:
#users = User.first
But it throw me an error, It show me should use rake db:migrate to generate table.
So i think i should export my data and use rake db:migrate to build my database structure, And import my data.
It's a little bother for a few table.
But, Actually i have too many tables (about 54), So i must write the 54 migrations manually.
So, is there a easy way to use exist database?
BTW, i use rails4
You could just dump your tables to schema.rb:
rake db:schema:dump
then convert it to your initial migration (001_initial_migration.rb):
class InitialMigration < ActiveRecord::Migration
def self.up
# put whole schema.rb here
end
def self.down
# drop everything
end
end
You don't need to write 54 migrations, one big one is enough.
There is also rmre gem, which tries to write your models for you.
you need not write migration for existed table,only write model for existed table,for example:
class User < AR
self.table_name = "users" # your existed table name in db
# attr_accessible :attrs
# Associations,remember indicate :foreign_key
end
if you want to add new table, do it as usual

Check if a table exists in Rails

I have a rake task that won't work unless a table exists. I'm working with more than 20 engineers on a website so I want to make sure they have migrated the table before they can do a rake task which will populate that respective table.
Does AR have a method such as Table.exists? How can I make sure they have migrated the table successfully?
In Rails 5 the API became explicit regarding tables/views, collectively data sources.
# Tables and views
ActiveRecord::Base.connection.data_sources
ActiveRecord::Base.connection.data_source_exists? 'kittens'
# Tables
ActiveRecord::Base.connection.tables
ActiveRecord::Base.connection.table_exists? 'kittens'
# Views
ActiveRecord::Base.connection.views
ActiveRecord::Base.connection.view_exists? 'kittens'
In Rails 2, 3 & 4 the API is about tables.
# Listing of all tables and views
ActiveRecord::Base.connection.tables
# Checks for existence of kittens table/view (Kitten model)
ActiveRecord::Base.connection.table_exists? 'kittens'
Getting the status of migrations:
# Tells you all migrations run
ActiveRecord::Migrator.get_all_versions
# Tells you the current schema version
ActiveRecord::Migrator.current_version
If you need more APIs for migrations or metadata see:
ActiveRecord::SchemaMigration
this is the ActiveRecord::Base class for the schema_migrations table
ActiveRecord::Migrator
where all the action happens when migrations are run
even if table is not exists:
model Kitten, expected table kittens
rails 3:
Kitten.table_exists? #=> false
I found this out while I was trying to remove a table via a migration:
drop_table :kittens if (table_exists? :kittens)
ActiveRecord::Migration.drop_table :kittens if (ActiveRecord::Base.connection.table_exists? :kittens)
works for Rails 3.2
This simpler form will become available in Rails 5:
drop_table :kittens, if_exists: true
Reference: https://github.com/rails/rails/pull/16366
And here's the Rails 5 ActiveRecord's CHANGELOG:
Introduce the :if_exists option for drop_table.
Example:
drop_table(:posts, if_exists: true)
That would execute:
DROP TABLE IF EXISTS posts
If the table doesn't exist, if_exists: false (the default) raises an exception whereas if_exists: true does nothing.
Rails 5.1
if ActiveRecord::Base.connection.data_source_exists? 'table_name'
drop_table :table_name
end
or
drop_table :table_name, if_exists: true
The proper way to do this is Model.table_exists?
class Dog < ApplicationRecord
# something
end
do_something if Dog.table_exists?

writing a Rake task for renaming a field name in a table in a Rails application

I am very new to rails application. I need to change the column name of a table ..
SO i browsed thru some sites and as thy mentioned i thought of writing migration file ..
class RenameNameToFirstnameInUsers < ActiveRecord::Migration
def self.up
rename_column 'users', 'name', 'first_name'
end
def self.down
rename_column 'users', 'first_name', 'name'
end
end
How to save this file and where ??
applicationname/db/migrate/
In what name i can save this ??
As far now i have seen many files there but all those have prefix of some big_number
And after saving this , how do i test it in my local??
the easiest way to do this is:
Rails3
rails generate migration RenameNameToFirstnameInUsers
Rails2
script/generate migration RenameNameToFirstnameInUsers
And then edit the created migration file, and migrate your db as normal.

Add Rows on Migrations

I'd like to know which is the preferred way to add records to a database table in a Rails Migration. I've read on Ola Bini's book (Jruby on Rails) that he does something like this:
class CreateProductCategories < ActiveRecord::Migration
#defines the AR class
class ProductType < ActiveRecord::Base; end
def self.up
#CREATE THE TABLES...
load_data
end
def self.load_data
#Use AR object to create default data
ProductType.create(:name => "type")
end
end
This is nice and clean but for some reason, doesn't work on the lasts versions of rails...
The question is, how do you populate the database with default data (like users or something)?
Thanks!
The Rails API documentation for migrations shows a simpler way to achieve this.
http://api.rubyonrails.org/classes/ActiveRecord/Migration.html
class CreateProductCategories < ActiveRecord::Migration
def self.up
create_table "product_categories" do |t|
t.string name
# etc.
end
# Now populate the category list with default data
ProductCategory.create :name => 'Books', ...
ProductCategory.create :name => 'Games', ... # Etc.
# The "down" method takes care of the data because it
# drops the whole table.
end
def self.down
drop_table "product_categories"
end
end
Tested on Rails 2.3.0, but this should work for many earlier versions too.
You could use fixtures for that. It means having a yaml file somewhere with the data you want to insert.
Here is a changeset I committed for this in one of my app:
db/migrate/004_load_profiles.rb
require 'active_record/fixtures'
class LoadProfiles < ActiveRecord::Migration
def self.up
down()
directory = File.join(File.dirname(__FILE__), "init_data")
Fixtures.create_fixtures(directory, "profiles")
end
def self.down
Profile.delete_all
end
end
db/migrate/init_data/profiles.yaml
admin:
name: Admin
value: 1
normal:
name: Normal user
value: 2
You could also define in your seeds.rb file, for instance:
Grid.create :ref_code => 'one' , :name => 'Grade Única'
and after run:
rake db:seed
your migrations have access to all your models, so you shouldn't be creating a class inside the migration.
I am using the latest rails, and I can confirm that the example you posted definitely OUGHT to work.
However, migrations are a special beast. As long as you are clear, I don't see anything wrong with an ActiveRecord::Base.connection.execute("INSERT INTO product_types (name) VALUES ('type1'), ('type2')").
The advantage to this is, you can easily generate it by using some kind of GUI or web front-end to populate your starting data, and then doing a mysqldump -uroot database_name.product_types.
Whatever makes things easiest for the kind of person who's going to be executing your migrations and maintaining the product.
You should really not use
ProductType.create
in your migrations.
I have done similar but in the long run they are not guaranteed to work.
When you run the migration the model class you are using is the one at the time you run the migration, not the one at the time you created the migration. You will have to be sure you never change your model in such a way to stop you migration from running.
You are much better off running SQL for example:
[{name: 'Type', ..}, .. ].each do |type|
execute("INSERT INTO product_types (name) VALUES ('#{type[:name]} .. )
end

Resources