How can I copy a mySQL Database in ruby on rails? - mysql

We are making a Ruby On Rails webapp where every customer gets their own database.
The database needs to be created after they fill out a form on our website.
We have a template database that has all of the tables and columns that we need to copy. How can I do this in programatically from ruby on rails?

I'm not sure what you mean but you can use ruby's command line functionality to dump the template database, create a new database and re-import it using the mysqldump program:
> mysqldump -uroot -proot templateDB > dump.sql
> mysql -uroot -proot --execute="CREATE DATABASE newDB"
> mysql -uroot -proot newDB < dump.sql
Here is a good description of invoking command line options from Ruby.

From any controller, you can define the following method.
def copy_template_database
template_name = "customerdb1" # Database to copy from
new_name = "temp" #database to create & copy to
#connect to template database to copy. Note that this will override any previous
#connections for all Models that inherit from ActiveRecord::Base
ActiveRecord::Base.establish_connection({:adapter => "mysql", :database => template_name, :host => "olddev",
:username => "root", :password => "password" })
sql_connection = ActiveRecord::Base.connection
sql_connection.execute("CREATE DATABASE #{new_name} CHARACTER SET latin1 COLLATE latin1_general_ci")
tables = sql_connection.select_all("Show Tables")
#the results are an array of hashes, ie:
# [{"table_from_customerdb1" => "customers"},{"table_from_customerdb1" => "employees},...]
table_names = Array.new
tables.each { |hash| hash.each_value { |name| table_names << name }}
table_names.each { |name|
sql_connection.execute("CREATE TABLE #{new_name}.#{name} LIKE #{template_name}.#{name}")
sql_connection.execute("INSERT INTO #{new_name}.#{name} SELECT * FROM #{template_name}.#{name}")
}
#This statement is optional. It connects ActiveRecord to the new database
ActiveRecord::Base.establish_connection({:adapter => "mysql", :database => new_name, :host => "olddev",
:username => "root", :password => "password" })
end
Note that I do not know for sure if this will keep foriegn key integrity. I think it depends a lot on how the template Database is created.

By using yaml_db
You need to install plugin, dump any rails database (including mysql) into data.yml file using rake task, change connection string to point to new database and then finaly load data.yml into any new database (including mysql) using another rake task. Very straightforward.

You could put your template schema creation code into a script which contains all of the required table/index/view/procedure creation statements, call it "template_schema.sql" or whatever and then just run the script on the database of your choice (from Ruby, if that's what you're after) and you're done.
The best approach is probably to have each database object in a separate file under source control (to make it easy to track changes on individual objects) and then have them merged into a single file as part of the deployment.

Related

Yii2 migration cant create DataBase

I create a table with migration and all works. But when i try yii migrate i catch error "database doesn exist". When i try to create DB in php admin, and after it use yii migrate, all works, tables was add to my db.
P.S db connection file work.
return [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=splynx',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
];
I Ask, how migrate can create DB?
If you want to use migrations on a table you HAVE TO create the database before that and then put the database with credentials in your DB file. then you will be able to use migrations.
You cannot migrate on a database which does not actually exist, as the error clearly says.
You can use migration to create rename tables but not create DB. Migration need to configure access to existing DB.
Firstly, create a database in localhost named splynx and then run the migrations

How can I extract data from one database, manipulate it, and insert it into another in Rails?

I have two databases (a legacy MySQL one and a new PostgreSQL one), and the schema for the new one was redesigned. As a result, I can't just dump the old database to YAML and load it into the the new one, since columns are named different things and may need to be manipulated. Is there an elegant way to do this?
It's actually fairly easy.
First you need to define the connection to your MySQL database in your database.yml. Let's call it legacy:
development:
adapter: postgresql
.....
test:
adapter: postgresql
.....
legacy:
adapter: mysql2
encoding: utf8
database: your_old_mysql_db
username: root
password:
host: localhost
port: 3306
You will need the mysql2 gem in your gemfile, alongside the pg gem!
Now just create models for each of the tables you want to connect to:
Here's one called LegacyUser, which will let you get the old users out of your MySQL database:
# app/models/legacy_user.rb
class LegacyUser < ActiveRecord::Base
establish_connection :legacy
self.table_name = "whatever_your_my_sql_user_table_name_is"
end
Now, in a Rake task you can pull data out of the MySQL table and stick it into your Postgres table like so:
# lib/tasks/import.rake
namespace :import do
desc "Import Users"
task users: :environment do
puts ""
puts "Importing Legacy Users:"
LegacyUser.find_each do |lu|
print "#{lu.id} - #{lu.first_name}"
u = User.new
u.email = lu.email
u.first_name = lu.first_name
u.last_name = lu.last_name
if u.save
puts "... saved"
else
puts "... bad: #{u.errors.full_messages.join(',')}"
end
end
end
end
Now you can just run:
rake import:users

Creating a Mysql user within a Rails controller action

Working on an app that wil be used by admin only to create multiple instances of another app.
In other words, app A will be used to create clones of app B on server and create all the configurations needed to run that cloned app on a subdomain new_clone.domain.com.
Managed to clone the app, created the apache config file, unicorn server settings file too. Managed to run rake db:create; db:migrate but I did this with the root user of mysql.
At the point where I clone the app, I generate a database.yml file for the new cloned app that has at this moment username and password set as root, but I woould like to have a different user for each cloned app.
The app A has a model called Subdomain, in the subdomains_controller.rb at the create action I do all the things, clone, generate config files, running rake tasks, etc... and also in this create action I need to create a new Mysql user with privileges for a specific database.
What I have tried so far, can't say I did much, I tried to run the mysql command within controller create action:
def create
if #subdomain.save
....
system "mysql -u root -p root; create database new_database;..."
....
else
....
end
end
but this puts my create action on hold until I type in the password, and even if I'll find a way to go over it I am not sure the rest of mysql commands will work. Probably there is a better way to add a Mysql user with one command line without going into mysql console.
Thank you.
As far as I understood, your create method runs under Rails app with root mysql user.
Then you can simply execute mysql commands via AR adapter:
# Create DB
ActiveRecord::Base.connection.execute("CREATE DATABASE IF NOT EXISTS \
`#{ActiveRecord::Base.sanitize(db_name)}` CHARACTER SET = `utf8` \
COLLATE = `utf8_general_ci`")
# Create User
ActiveRecord::Base.connection.execute("REPLACE INTO mysql.user \
(Host, User, Password) VALUES(\"localhost\", \
\"#{ActiveRecord::Base.sanitize(db_user)}\", \
PASSWORD(\"#{ActiveRecord::Base.sanitize(db_password)}\"))")
# Grant access
ActiveRecord::Base.connection.execute("GRANT ALL PRIVILEGES ON \
`#{ActiveRecord::Base.sanitize(db_name)}`.* TO \
`#{ActiveRecord::Base.sanitize(db_user)}`")
# Apply
ActiveRecord::Base.connection.execute("FLUSH PRIVILEGES")
Thanks to Yuriy's answer I got it working in a shorter way:
def create_mysql_user
#db_name = "#{#subdomain.name}_domain_production"
#db_user = "#{#subdomain.name}_user"
#db_password = "#{#subdomain.name}domain_password"
ActiveRecord::Base.connection.execute("GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER,
INDEX ON `#{#db_name}`.* TO #{ActiveRecord::Base.sanitize(#db_user)}#localhost
IDENTIFIED BY #{ActiveRecord::Base.sanitize(#db_password)};")
# Apply
ActiveRecord::Base.connection.execute("FLUSH PRIVILEGES")
end

Backup MySQL via php, in a Symfony application

I'm trying to do a php script to backup my database.
Here's what I've tried so far :
$command = "mysqldump -u [username] -p [password] [databasename] | gzip > db.sql.gz";
$this->output = system($command);
How do I get the password and
username from databases.yml ?
How can I do a script that sends me
the backup file, instead of saving it
on the server (à la phpmyadmin) ?
You can create a symfony task. If you pass in an environment (i.e. dev, prod) or connection you get access to the Doctrine connection manager and create a connection. You can use that connection to make a database dump or get the connection details from the connection manager.
You can use the doctrine insert sql task as template for your task. I've done similar in the past.

Accessing database.yml info through a rake task

I'm trying to write a rake task for loading data into my database. My plan is do something like
system "mysql -u foo -pbar database < backup.sql"
but I need to access the config/database.yml data for getting the user, pass and database info. The trick is I don't want to "parse" this file but to access this info in the same way tasks like rake db:reset do.
How can I do that?
This will work.
task :demo_using_db_config => :environment do
db_config = Rails.application.config.database_configuration[Rails.env]
system "mysql -u#{db_config['username']} -p#{db_config['password']} #{db_config['database']} < backup.sql"
end
Since this is environment specific, we want the task to depend on the :environment task.
Alternatively, if you are using ActiveRecord, you can get to this information like below:
abcs = ActiveRecord::Base.configurations
puts abcs[Rails.env]["username"]
puts abcs[Rails.env]["password"]
This works in rake tasks and elsewhere.
In Rails 3, from the console, you can type the following to see various database login credentials you defined in database.yml
config = Rails.application.config.database_configuration
In your rake file, you could specify something like this:
task :mysqlimport_table
db_config = Rails.application.config.database_configuration[Rails.env]
sh "mysqlimport -u#{db_config['username']} -p#{db_config['password']} #{db_config['database']} --default-character-set=utf8 --local <path_to_your_file>"
end
task :mysqlrun_sql_script
db_config = Rails.application.config.database_configuration[Rails.env]
sh "mysql -u#{db_config['username']} -p#{db_config['password']} -D#{db_config['database']} < <path_to_your_sql_file>"
end
Like this:
require 'yaml'
conf = YAML.load_file("path/to/database.yml")