My app, must work with multiple db's for many reasons. I work on custom model for db connection establishing, where I need to establish new db connection, based on arg's, .
So, for example, before establishing new connection using:
ActiveRecord::Base.establish_connection new_config
Where new_config is customized clone, of database.yml
I want to check whether new DB exists before any db connections establishing. So I need a function db_exists? db_name that will return boolean value, based on whether db exists or not.
It seems a bit illogical to be able to check whether or not a database exists without a connection to that database, but that may just be me.
I recommend you consider using a rescue block to attempt the connection and then handle the appropriate exceptions.
The exceptions you can receive from that attempt are discussed here.
Just ran across a very good discussion on using rescue here.
We use Rails apps to manage databases themselves, so have to do stuff like this all the time. It's perfectly reasonable to want to know about databases besides the current Rails data store. It's a lot like checking for the existence of a file that's not part of the current Rails app.
Here's a solution that may be useful in certain situations (this for MySQL):
def db_exists?(db_name)
ActiveRecord::Base.connection.execute("SHOW DATABASES LIKE '#{db_name}'").size > 0
end
You have to have SOME database connection but it certainly does not have to be for the database you are querying for existence. (Note this implementation is NOT protected against sql injection... it requires you only pass in clean, valid db_name.)
Related
Context
I'm building a SaaS where users can create their own websites (like Wix or SquareSpace).
That's what happens behind scenes:
My app has its main database which stores users
When a user creates his website, an external database is created to store its data
SQL file runs in this external database to set default settings
Other users shall create their websites simultaneously
Approach
To create a new database and establish connection I do the following:
ActiveRecord::Base.connection.execute("CREATE DATABASE #{name}")
ActiveRecord::Base.establish_connection(<dynamic db data>)
Then I execute sql code in the db by doing:
sql = File.read(sql_file.sql)
statements = sql.split(/;$/)
statements.pop
ActiveRecord::Base.transaction do
statements.each do |statement|
connection.execute(statement)
end
end
Then I reestablish connection with main db:
ActiveRecord::Base.establish_connection :production
Problem
Establishing connection to dynamic database makes application's main database inacessible for a while:
User A is creating a website (establishes dynamic database connection)
User B tries to access his user area (which requires application's main db data)
Application throws an error because it tries to retrieve data of app-main-db (which connection is not established at the moment)
How can I handle many users creating their websites simultaneously without databases conflict?
In other words, how can I establish_connection with more than one database in parallel?
NOTE:
It is not the same as connecting to multiple databases through database.yml. The goal here is to connect and disconnect to dynamic created databases by multiple users simultaneously.
This gem may help. However,you may need to rename some of your models to use the external database namespace instead of ApplicationRecord
https://github.com/ankane/multiverse
I admit that this doesn't answer the core of your initial question but IMO this probably needs to be done via a separate operation, say a pure SQL script triggered somehow via a queue.
You could have your rails app drop a "create message" onto a queue and have a separate service that monitors the queue that does the create operations, and then pass a message with info back to the queue. The rails application monitors the queue for these and then does something with the information.
The larger issue is decoupling your operations. This will help you down the road with things like maintenance, scaling, etc.
FWIW here is a really cool website I found recently describing a lot of popular queuing services.
Probably not the best approach but it can be achieved by calling an external script that creates the database, in a separated ruby file:
Create create_database.rb file in lib folder
Put db creation script inside this file
ActiveRecord::Base.connection.execute("CREATE DATABASE #{name}")
ActiveRecord::Base.establish_connection(<dynamic db data>)
Execute with Rails Runner
rails runner lib/create_database.rb
or with system, if you want to call it from controller
system("rails runner lib/create_database.rb")
This way you can create and access multiple databases without stopping your main database.
Passing arguments
You can pass arguments to your script with ARGV:
rails runner lib/create_database.rb db_name
And catch it inside the script with ARGV[0]:
name = ARGV[0]
puts name
> db_name
So in my company we are slowly moving to Rails instead of PHP(Code Igniter to be precise).
So, our actual PHP App is using a Mysql DB and I'd like to connect a new Rails app to this DB but meanwhile our PHP is still running, so I can't change the DB.
I don't really know where I should start to use all the rails features (Or at least as much as possible).
There shouldn't be any harm in connecting your rails app to an existing database. You will need to watch for anything that goes against rails conventions (table names are plurals of models, for example) and either change the database (and your php app) or program around the problem in rails.
But the first step is simply to connect to the database and make models for the existing tables and see what works and what doesn't.
After that, post here with any specific problems.
As a suggestion, take a backup of your database and start out programming against that to build your application and be sure everything works safely.
Well, first of all you should setup the connection in config/database.yml and then start to generate the scaffolding (models, views and controllers) table by table (check the Rails generate command). I am not really sure if you have already generated the app though. Anyway, the generator will also generate a migration script that you obviously dont want to run as the db is already there.
Hope this helps a bit.
Anyway, some resources:
http://guides.rubyonrails.org/
http://railsapps.github.io/
There are two aspects of a Rails app to consider for this scenario:
1: the database connection
Simply put the credentials for this database into database.yml.
A model like "User" will by default attempt to find records and attribute definitions in a table called "users". ActiveRecord will assume there's an auto-incrementing integer primary key on each table. When saving records, it will attempt to write to columns called created_at and updated_at. Those are a few things to be mindful of when making and using the connection.
2: the database migrations
Rails uses migration files to manage a sequence of changes to the database structure. Under normal conditions, someone building a Rails app will be starting with an empty database.
In the case of an existing database, I would recommend making a migration something like:
class BuildLegacyDbStructure < ActiveRecord::Migration
def up
Mysql2.connection.execute_some_sql_file( # made-up function
Rails.root.join('path', 'to', 'file')
)
end
def down
# reverse those changes; bring DB down to blank state
end
end
Another option would be to disable Rails/ActiveRecord's migration-based management of the database entirely. For example Rails will generate a migration when you generate a new model. So if you have an existing users table in your PHP app, and you'd like to make a rails model to use this table, you'd run something like rails generate model User --no-migration.
Im creating a database via a "code first" application, the sql server contains no databases.
The application runs fine, creates the database and seeds the data i have defined in my initializer.
a service i have running tries to add some data to the database for the first time. i get the error:
The model backing the 'yyyContext' context has changed since the database was created. Either manually delete/update the database, or call Database.SetInitializer with an IDatabaseInitializer instance. For example, the DropCreateDatabaseIfModelChanges strategy will automatically delete and recreate the database, and optionally seed it with new data.
There should be no changes since the database was created and when then service runs.
I'm running EF4.1, and the database doesn't exist so unlike questions with similar titles:
Database.SetInitializer<YourContext>(null);
Isn't the solution for me.
Any ideas about what could be wrong are welcome.
Doh! moment, turns out the service wasnt using the same connectionstring as the other app.
the reason the databases didnt look the same must be because earlier in development i started the main app with no connectionstring aswell, so it provisioned a local instance database for itself to use.
Then later when i was trying to use the service, it was trying to access the same database from earlier, and the model changed significantly since then.
I pointed the connectionstring to the correct database and everything worked from there.
I have a django applicaiton with multiple databases. The default database is on the local machine. There is also a remote mysql database which is used for some write operations, but it is not always up. When the server is down, mysqldb raises an OperationalError.
I would like have a local sqlite database called 'fallback' which would accept the data if the mysql server is down. I realize that this involves at try/except clause in django.db.mysql.base, but I am not quite sure where to go from there. Has anyone tried something similar? Do you have suggestions on a better way to handle this?
You could probably use Database Routers in combination with a custom base Model class that overrides the save method. Wrap it in a try..catch, and if the OperationalError occurs, provide some hints so your database router can determine if the fallback needs to be used.
I think this will be the cleanest way, rather than modifying the django code itself.
Is there a way within Rails/AR to create a new mysql database at runtime?
What i recommend is to prepare standalone script readable only by specified user and execute it from rails with system command with db name as parammeter
The quick and dirty answer is:
Make sure the MySQL user your app is connecting as is allowed to create databases.
Create the database using a SQL statement:
ActiveRecord::Base.connection.execute('CREATE DATABASE IF NOT EXISTS new_database');
For simplicity's sake I'd suggest not even using ActiveRecord for this. AR is really designed to work with preconfigured databases, and even though you can create databases where you'll really run into problems is in trying to connect to and use those DBs on the fly.
You might be better off using Brian Lopez's mysql2 gem (in addition to AR for your app's main DB):
https://github.com/brianmario/mysql2
In addition to being pretty fast and modern, its API is a lot easier to work with than the raw mysql library (which is what AR uses under the hood, including connection.execute).